SpringBoot对非关系型数据库NoSql的支持

时间:2021-01-04 08:46:05

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);
}
}

访问http://localhost:8080/save 可以看到
SpringBoot对非关系型数据库NoSql的支持
数据已经被保存到MongoDB中(可视化工具为RoboMongo),Mongo的安装请参照:MongoDB学习(三)MongoDB 3.2.8的使用详解
测试两个查询方法的结果如下图
SpringBoot对非关系型数据库NoSql的支持

查询姓名
SpringBoot对非关系型数据库NoSql的支持

源码地址

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();
}

}

运行之后我们可以看到。访问http://localhost:8080/test 会发现数据可视化中出现了如下数据
SpringBoot对非关系型数据库NoSql的支持

获取字符数据http://localhost:8080/getStr
SpringBoot对非关系型数据库NoSql的支持

获取实体数据http://localhost:8080/getPerson
SpringBoot对非关系型数据库NoSql的支持

代码

总结

本篇博客主要讲解了SpringBoot与两种Nosql数据库的结合,比较简单。后续会继续深入的探讨SpringBoot的知识。希望与大家多交流。