这篇博客是一篇笔记博客,看的是黑马的瑞吉外卖的视频。【好记性不如烂笔头】

在Spring Boot项目中,可以使用Spring Data Redis来简化Redis操作。

首先需要导入maven坐标

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

在Spring Boot中的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spring:
application:
name: spring-redis
redis:
host: localhost
port: 6379 #默认端口号
#password: 123456
database: 0 #默认提供了16个数据库(可以在配置文件中改) 默认操作0号数据库,可以在命令行 select 1 选择1号数据库,
jedis:
#Redis连接池配置
pool:
max-active: 8 #最大链接数
max-wait: 1ms #连接池最大阻塞等待时间
max-idle: 4 #连接池的最大空闲连接
min-idle: 0 #连接池的最小空闲连接

Spring Data Redis中提供了一个高度封装的类: RedisTemplate,针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:

  • ValueOperations 简单的K-V操作
  • SetOperations set类型数据操作
  • ZSetOperations zset类型数据操作
  • HashOperations 针对Map类型的数据操作
  • ListOperations 针对list类型的数据操作

说明:RedisTemplate 这个类可以由Spring Boot自动装配的,前提是配置好

spring-boot-test-autoconfigure-..这个jar包中,META-INF目录下有个spring.factories【它进行了很多自动化配置】文件。Spring Boot项目在运行的时候,就会加载这个文件,在这个文件里找到 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,按Ctrl点进去,就可以看到一个配置类。

1
2
3
4
5
6
7
8
9
@Bean
@ConditionalOnMissingBean( //在容器中没有这个Bean时,加载
name = {"redisTemplate"}
)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}

所以可以直接使用@Autowired注解,直接注入。

1
private RedisTemplate<String,String> redisTemplate;

这是指定了泛型的,也可以不指定泛型,最后再说明这两个之间区别是什么。

代码示范

ValueOperations:简单的K-V操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
void testString() {
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
//添加
valueOperations.set("country","China");
//获取
String country = valueOperations.get("country");
System.out.println(country);

//设置超时时间
valueOperations.set("name","zhangsan",5, TimeUnit.SECONDS);

//如果存在就不设置
valueOperations.setIfAbsent("name","lisi");
String name = valueOperations.get("name");
System.out.println(name);
}

HashOperations 针对Map类型的数据操作

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
@Test
void testHash(){
//添加
HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
hashOperations.put("002","name","zhangsan");
hashOperations.put("002","age","23");
hashOperations.put("002","address","xian");

//获取所有key
Set<String> keys = hashOperations.keys("002");
for (String key : keys) {
String value = hashOperations.get("002", key);
System.out.println(key+":"+value);
}
//获取所有的value
List<String> values = hashOperations.values("002");
System.out.println(values);

//批量添加
Map<String,String> user = new HashMap<>();
user.put("name","lisi");user.put("age","29");user.put("address","bj");
hashOperations.putAll("001",user);

//批量获取
List<String> list = new ArrayList<>();
list.add("name");list.add("age");list.add("address");
List<String> multiGet = hashOperations.multiGet("001", list);
System.out.println(multiGet);
//批量获取2
Map<String, String> map = hashOperations.entries("001");
System.out.println(map);
}

ListOperations 针对list类型的数据操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
void testList(){
ListOperations<String, String> listOperations = redisTemplate.opsForList();

//添加
listOperations.leftPush("mylist","1");
listOperations.leftPushAll("mylist","2","3","4","5");//添加多个

//获取长度
long size = listOperations.size("mylist");
for (long i = 0; i < size; i++) {
String value = listOperations.leftPop("mylist");//弹出
System.out.println(value);
}

List<String> mylist = listOperations.range("mylist", 0, -1);
System.out.println(mylist);
}

1,2,3,4,5依次从左边进

5,4,3,2,1依次从左边出

Redis的list类型类似双端队列

SetOperations set类型数据操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
void testSet(){
SetOperations<String, String> setOperations = redisTemplate.opsForSet();
//添加
setOperations.add("myset","zhangsan","lisi","wangwu");

//获取 members(key)
Set<String> stringSet = setOperations.members("myset");
System.out.println(stringSet);

//删除
setOperations.remove("myset","lisi","wangwu");
Set<String> myset = setOperations.members("myset");
System.out.println(myset);
}

ZSetOperations zset类型数据操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
void testZset(){
ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
//添加
zSetOperations.add("myzset","a",10);
zSetOperations.add("myzset","b",12);
zSetOperations.add("myzset","c",9);
zSetOperations.add("myzset","a",13);
//获取
Set<String> myzset = zSetOperations.range("myzset", 0, -1);
System.out.println(myzset);

//改变分数
zSetOperations.incrementScore("myzset","b",10);

myzset = zSetOperations.range("myzset", 0, -1);
System.out.println(myzset);

//删除
zSetOperations.remove("myzset","b");

myzset = zSetOperations.range("myzset", 0, -1);
System.out.println(myzset);
}

公共操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
void testcommon(){
//获取Redis所有key
Set<String> keys = redisTemplate.keys("*");
System.out.println(keys);
//判断某个key是否存在
Boolean key = redisTemplate.hasKey("name");
System.out.println(key);
//删除指定的key
redisTemplate.delete("myset");
keys = redisTemplate.keys("*");
System.out.println(keys);
//获取指定的key对应的value数据类型
DataType type = redisTemplate.type("001");
System.out.println(type);
}

RedisTemplate指定泛型和不指定泛型的区别

其实区别就是在操作redis时,key和value的序列化方式不同。用代码测一下。

指定泛型

1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootTest
class SpringRedisApplicationTests {

@Autowired
private RedisTemplate<String,String> redisTemplate;

@Test
void test(){
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
valueOperations.set("name","zhangsan");
}
}

在redis存储了一个key为name的数据,value为zhangsan。

然后打开命令行

1
2
3
4
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> get name
"zhangsan"

这很正常吧

不指定泛型

重启redis服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SpringBootTest
class SpringRedisApplicationTests {
// @Autowired
// private RedisTemplate<String,String> redisTemplate;

@Autowired
private RedisTemplate redisTemplate;

@Test
void test(){
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("name","zhangsan");
}
}

在redis存储了一个key为name的数据,value为zhangsan。

然后打开命令行

1
2
3
4
127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04name" #发现不一样的了吧
127.0.0.1:6379> get name
(nil) #获取不到

这就是序列化方式不一样。

然后再不指定泛型的情况下,配置一下RedisTemplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();

//默认的key序列化器为:JdkSerializationRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());

redisTemplate.setConnectionFactory(factory);

return redisTemplate;
}
}

重启redis服务,然后在运行以上程序,然后再在命令行试一下

1
2
3
4
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> get name
"\xac\xed\x00\x05t\x00\bzhangsan"

"\xac\xed\x00\x05t\x00\bzhangsan" 出现这个的原因是,没有设置value的序列化。

总结

最后可以看出

private RedisTemplate<String,String> redisTemplate;泛型的指定可以决定RedisTemplate的key和value的序列化方式。

__END__