整合Spring Data Redis
SpringData
他是Spring的一个子项目。用于简化数据库访问, 支持NoSQL和关系型数据库。其主要目标是使得数据库的访问变得方便快捷
开发人员唯一要做的就是声明持久层的接口,其他的操作就交给 Sprign Data JPA完成。JPA能够根据一定规则的方法名来实现一些的逻辑操作。
SpringData所支持的NoSQL存储
- MongoDB(文档数据库)
- Neo4j(图形数据库)
- Redis(键值存储)
- Hbase(列族数据库)
SpringData项目支持的关系型数据库
- JDBC
- JPA
spring-data-redis简介
Spring-data-redis是spring大家族的一部分,提供了在srping应用中通过简单的配置访问redis服务,对reids底层开发包(Jedis, JRedis, and RJC)进行了高度封装,RedisTemplate提供了redis各种操作。
Spring-Data-Redis项目(简称SDR)对Redis的Key-Value数据存储操作提供了更高层次的抽象,类似于Spring Framework对JDBC支持一样。
spring-data-redis针对jedis提供了如下功能:
- 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
- 针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
- ValueOperations:简单K-V操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:针对map类型的数据操作
- ListOperations:针对list类型的数据操作
整合Redis
准备依赖
pom.xml 文件下添加如下依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--连接池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
编写配置文件
yaml文件如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21spring:
redis:
host: 192.168.56.101
port: 6379
password: 654321
database: 0 # 数据库索引,默认0
timeout: 5000 # 连接超时,单位ms
# 哨兵模式
sentinel:
master: mymaster
nodes: 192.168.56.101:26379,192.168.56.101:26380 # 哨兵的IP:Port列表
# 集群模式
# cluster:
# nodes: 192.168.40.201:7100,192.168.40.201:7200,192.168.40.201:7300,192.168.40.201:7400,192.168.40.201:7500,192.168.40.201:7600
# max-redirects: 3 # 重定向的最大次数
lettuce: # jedis或lettuce, 连接池配置,springboot2.0中使用jedis或者lettuce配置连接池,默认为lettuce连接池
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池分配连接最大阻塞等待时间(阻塞时间到,抛出异常。使用负值表示无限期阻塞)
max-idle: 8 # 连接池中的最大空闲连接数
min-idle: 0 # 连接池中的最小空闲连接数
测试
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package tk.fulsun.demo;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
/**
* @author fulsun
* @description: 主测试类
* @date 5/27/2021 4:27 PM
*/
class ApplicationTest {
private RedisTemplate redisTemplate;
public void testStringRedisTemplate() {
ValueOperations<String, String> vo = redisTemplate.opsForValue();
// 使用redis-cli查看key
// 发现hello的key变成了 \xac\xed\x00\x05t\x00\x05hello
vo.set("hello", "世界world_" + UUID.randomUUID().toString());
String hello = vo.get("hello");
System.out.println("之前保存的数据:" + hello);
}
}
Redistemplate
- Springboot中自动集成了redistemplate两种实例化方式
redistemplate<object,object>
redistemplate<string,string>
- 这两种方式并不好用,数据存入中文之后会出现Ascll码,让人看不懂
- 第一种,存储的方式则为jdk实例化,不太好懂,数据也看不清楚
- 第二种的话,我需要手动将对象数据进行json转化,影响代码效率,存储起来也非常麻烦
自定义redis配置
重新配置
RedisTemplate<String,Object>
,修改默认的序列号方式为JdkSerializationRedisSerializer
—>Jackson2JsonRedisSerializer
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68package tk.fulsun.demo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
// @Configuration
public class RedisConfig {
/** 自定义RedisTemplate - 配置序列化配置,默认是jdk */
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// 为了开发的方便,一般直接使用 <String, Object>
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory); // redis连接的线程安全工厂,源码也是这样配置的
// Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =
new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 关闭自动检测。使用两个属性ALL(getter和setter)和字段来序列化和反序列化为json。
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定jackson只使用字段
// om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
// om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入类型,不指定那存储到redis里的数据将是没有类型的纯json,解析后是一个LinkHashMap类型
// 指定序列化输入类型,java获取到数据后,将会将数据自动转化为转换前的类型
// NON_FINAL:整个类、除final外的的属性信息都需要被序列化和反序列化
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
om.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.WRAPPER_ARRAY);
// 解决jackson2无法序列化LocalDateTime的问题,这里扩展一个LocalDateTime类型,它是日期类型对象
// jdk1.8出的(并且这个类是不可变的和线程安全的,可以研究一下它的API),当然还需要对这个对象进行json格式的转换,如下图:
om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);
om.registerModule(new JavaTimeModule());
jackson2JsonRedisSerializer.setObjectMapper(om);
// String 的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
// 非spring容器必须执行
template.afterPropertiesSet();
return template;
}
}重新测试,可以正常看到key的值为hello
操作5种类型
Hash类型的操作:经常用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34//(1)存入值
public void boundHashOpsSet(){
redisTemplate.boundHashOps("namehash").put("country1","中国");
redisTemplate.boundHashOps("namehash").put("country2","日本");
redisTemplate.boundHashOps("namehash").put("country3","韩国");
}
//(2)提取所有的KEY
public void boundHashOpsKeys(){
Set keys = redisTemplate.boundHashOps("namehash").keys();
System.out.println(keys);
}
//(3)提取所有的值
public void boundHashOpsValues(){
List values = redisTemplate.boundHashOps("namehash").values();
System.out.println(values);
}
//(4) 根据KEY提取值
public void boundHashOpsByKey(){
Object name = redisTemplate.boundHashOps("namehash").get("country1");
System.out.println(name);
}
//根据KEY移除值
public void boundHashOpsDelByKey(){
redisTemplate.boundHashOps("namehash").delete("country2");
}值类型的操作:因为操作数量少,所以不常用
1
2
3
4
5
6
7
8
9
10
11
12
13
public void setValue(){
redisTemplate.boundValueOps("name").set("王五");
}
public void getValue(){
Object name = redisTemplate.boundValueOps("name").get();
System.out.println(name);
}
public void deleteValue(){
redisTemplate.delete("name");
}set类型的操作:因为操作数量少,所以不常用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23/** 存入值 */
public void boundSetOpsAdd() {
redisTemplate.boundSetOps("nameset").add("曹操"); // 放入值
redisTemplate.boundSetOps("nameset").add("刘备");
redisTemplate.boundSetOps("nameset").add("孙权");
}
/** 提取值 */
public void boundSetOpsGet() {
Set names = redisTemplate.boundSetOps("nameset").members(); // 取出值
System.out.println(names);
}
/** 删除集合中的某一个值 */
public void boundSetOpsDelete() {
redisTemplate.boundSetOps("nameset").remove("曹操");
}
/** 删除整个集合 */
public void boundSetOpsDeleteAll() {
redisTemplate.delete("nameset");
}list类型的操作:因为操作数量少,所以不常用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30/** 右压栈:后添加的对象排在后边 右压栈用的多,因为快,原理是 */
public void boundListrightPush() {
redisTemplate.boundListOps("namelist").rightPush("赵子龙");
redisTemplate.boundListOps("namelist").rightPush("张飞");
redisTemplate.boundListOps("namelist").rightPush("关羽");
}
/** 显示右压栈集合 */
public void boundListRange() {
List namelist = redisTemplate.boundListOps("namelist").range(0, 10);
System.out.println(namelist);
}
/** 查询:根据索引查询集合某个元素 */
public void boundListIndex() {
Object name = redisTemplate.boundListOps("namelist").index(1);
System.out.println(name);
}
/** 删除: 根据值移除集合某个元素 */
public void bondListRemove() {
redisTemplate.boundListOps("namelist").remove(1, "关羽");
}
/** 删除: 删除全部 */
public void bondListDelete() {
redisTemplate.delete("namelist");
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 凉月の博客!
评论