1. 程式人生 > >SpringBoot對非關係型資料庫NoSql的支援

SpringBoot對非關係型資料庫NoSql的支援

NoSql是對於所有不使用關係作為資料管理的資料庫系統的總稱,NoSql的特點主要是不使用sql作為查詢語言。資料儲存也不是固定的表和欄位
NoSql資料庫主要有文件儲存型(MongoDB),圖形關係儲存型(Neo4j),鍵值對儲存型(Redis)

Spring對MongoDB的支援

Spring對MongoDB的支援主要是通過Spring Data MongoDB來實現的。

Spring Data MongoDB提供的註解支援

  • @Document 對映領域物件與MongoDB的一個文件
  • @Id 對映當前屬性是ID
  • @DbRef 當前屬性將參考其他文件
  • @Field 為文件的屬性定義名稱
  • @Version 將當前屬性作為版本

資料操作MongoTemplete的支援

MongoTemplete為我們提供了資料放我那和操作的方法,我們還需要為MongoClient和MongoDbFactory來配置資料庫連線屬性。

    @Bean
    public MongoClient client() throws UnKnownHostException{
    MongoClient client = new MongoClient(new ServerAddress("127.0.0.1",27017))
    }
    @Bean
    public MongoDbFactory mongoDbFactory
() throws Exception{ String database = new MongoClientURI("mongodb://localhost/test").getDatabase(); return new SimpleMongoDbFactory(client(),database); } @Bean public MongoTemplete mongoTemplete(MongoDbFactory mongoDbFactory)throws UnKnownHostException{ return new MongoTemplete(mongoDbFactory); }

@Repository的支援

Spring提供了類似JpaRepository的支援MongoRepository的支援
在自定義的Repository介面中繼承即可

public interface PersonRepository extends MongoRepository<Person,String>{
}

如何開啟MongoRepository,則需要在配置類或是Spring的入口類中加入註解@EnableMongoRepository

SpringBoot對MongoDB的支援

springBoot為我們提供了一些預設屬性例如預設埠27017,預設伺服器為localhost。預設資料庫為test等
我們開始使用之前除了上述知識需要掌握以外只需引入spring-boot-starter-data-mongodb依賴外,無需任何其他配置。

SpringBoot+MongoDB實戰

首先依然是準備程式碼

程式碼準備

pom檔案引入

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

在這裡要注意的是,我們這裡只是測試MongoDB單資料來源的情況,如果要進行多資料來源測試,那麼需要進行額外的配置,如果這裡引入了mysql的依賴。那麼程式會報錯

Cannot determine embedded database driver class for database type NONE

接下來是實體的準備
Person類

@Document
public class Person {
    @Id
    private  String id;
    private  String name;
    private  Integer age;
    @Field("locs")
    private Collection<Location> locations = new LinkedHashSet<>();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public Collection<Location> getLocations() {
        return locations;
    }

    public void setLocations(Collection<Location> locations) {
        this.locations = locations;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setAge(Integer age) {
        this.age = age;

    }

    public Person(String name, Integer age) {
        super();
        this.name = name;
        this.age = age;
    }
}

Location類

public class Location {
    private  String place;

    private  String year;

    public String getPlace() {
        return place;
    }

    public void setPlace(String place) {
        this.place = place;
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }

    public Location(String place, String year) {
        super();
        this.place = place;
        this.year = year;
    }
}

@Document註解對映領域模型和MongoDB的文件
@Id註解表明這個屬性為文件的Id
@Field註解此屬性在文件中的名稱為locs,locations屬性將以陣列形式存在當前資料記錄中

Repository

    Person findByName(String name);

    @Query("{'age':?0}")
    List<Person> withQueryFindByAge(Integer age);

從上述方法可見,MongoRepository仍然支援類似於JPA的方法名和Query查詢

Controller層

@RestController
public class DataController {
    @Autowired
    PersonRepository personRepository;

    @RequestMapping("/save")
    public  Person save(){
        Person p = new Person("zhaozhen",23);
        Collection<Location> locations = new LinkedHashSet<>();
        Location loc1 =new Location("上海","2012");
        Location loc2 =new Location("合肥","2013");
        Location loc3 =new Location("武漢","2014");
        Location loc4 =new Location("北京","2015");
        locations.add(loc1);
        locations.add(loc2);
        locations.add(loc3);
        locations.add(loc4);
        p.setLocations(locations);
        return  personRepository.save(p);
    }

    @RequestMapping("/q1")
    public  Person q1(String name){
        return  personRepository.findByName(name);
    }

    @RequestMapping("q2")
    public List<Person> q2 (Integer age){
        return  personRepository.withQueryFindByAge(age);
    }
}

查詢姓名
查詢姓名

原始碼地址

Spring對Redis的支援

Redis是一個基於鍵值對的開源記憶體資料儲存,當然Redis也可以作為資料快取。Spring 對Redis的支援是通過Spring Data Redis來實現的,SpringData JPA為我們提供了連線相關的connectionFactory和資料操作相關的RedisTemplete。根據Redis的不同的java客戶端有如下

connectionFactory劃分

  • JedisConnectionFactory ,使用Jedis作為Redis客戶端
  • JredisConnectionFactory,使用Jredis作為Redis客戶端
  • LettuceConnectionFactory,使用Lettuce作為Redis客戶端
  • SrpConnectionFactory,使用Squllara/redis-protocol作為Redis客戶端

資料操作相關的RedisTemplete主要分為RedisTemplete和StringRedisTemplete兩個模板進行資料操作。前者主要處理物件的資料操作,後者主要處理String型別的資料操作。兩種資料操作模板主要有以下方法

操作方法

  • opsForValue 操作只有簡單屬性的資料
  • opsForList 操作含有List的資料
  • opsForSet 操作含有Set的資料
  • opsForZSet操作含有ZSet(有序的set)的資料
  • opsForHash 操作含有hash的資料

Redis的序列化Serializer

當我們的資料儲存到Redis的時候,我們的鍵值對是通過Serializer序列化到資料庫的RedisTemplete預設使用的是JdkSerializationRedisSerializer,StringRedisTemplete預設使用的是StringRedisSerializer,除此之外Spring Data JPA還為我們提供如下Serializer:GenericToStringSerializer,Jackson2JsonRedisSerializer,JacksonJsonRedisSerializer,OxmSerializer.

SpringBoot對Redis的支援

SpringBoot的自動配置為我們自動預設配置了JedisConnectionfactory、RedisTemplete,StringRedisTemplete,讓我們可以直接使用Redis作為資料儲存。我們也可以在properties檔案中以spring.redis開頭作為字首配置Redis的屬性。

SpringBoot對Redis的實踐

前期準備

首先需要在本機安裝Redis 。教程傳送門:在windows上搭建Redis環境
然後下載一個Redis管理的視覺化工具。例如Redis client或者Redis Desktop Manager

程式碼準備

實體類

public class Person implements Serializable {
    private  String id;
    private String name;
    private Integer age;

    public  Person(){
        super();
    }
    public Person(String id, Integer age, String name) {
        super();
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

Dao層

@Repository
public class PersonDao {
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Resource(name = "stringRedisTemplate")
    ValueOperations<String,String> valueOpsStr;

    @Autowired
    RedisTemplate<Object,Object> redisTemplate;
    @Resource(name = "redisTemplate")
    ValueOperations<Object,Object> valueOps;
    //儲存字串型別
    public void stringRedisTempleteDemo(){
        valueOpsStr.set("xx","yy");
    }
    //儲存物件型別
    public  void  save(Person person){
        valueOps.set(person.getId(),person);
    }
    //獲得字串
    public  String getString(){
        return  valueOpsStr.get("xx");
    }
    //獲取物件型別
    public Person getPerson(){
        return (Person) valueOps.get("1");
    }
}

SpringBoot為我們配置了RedisTemplete。而RedisTemplete使用的是JdkSerializationRedisSerializer(用二進位制儲存資料)。這個對後續視覺化工具的演示不太直接。
我們在此自己配置RedisTemplete並定義Serializer。

入口類

@SpringBootApplication
public class SpringBootRedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootRedisApplication.class, args);
    }
    @Bean
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
        template.setConnectionFactory(redisConnectionFactory);

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        template.setValueSerializer(jackson2JsonRedisSerializer); //1
        template.setKeySerializer(new StringRedisSerializer()); //2

        template.afterPropertiesSet();
        return template;
    }

}

控制器

@RestController
public class DataController {

    @Autowired
    PersonDao personDao;

    @RequestMapping("/test")
    public void set(){
        Person p = new Person("1",23,"zhaozhen");
        personDao.save(p);
        personDao.stringRedisTempleteDemo();
    }

    @RequestMapping("/getStr")
    public String getStr(){
        return personDao.getString();

    }
    @RequestMapping("/getPerson")
    public Person getPerson(){
        return  personDao.getPerson();
    }

}

程式碼

總結

本篇部落格主要講解了SpringBoot與兩種Nosql資料庫的結合,比較簡單。後續會繼續深入的探討SpringBoot的知識。希望與大家多交流。