docker安装Redis参考我另一篇博客Docker安装Redis及持久化
一、Get-Started
依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--Apache对象池技术,包括RedisConnecttionFactory等,引入这个依赖就不需要自己配置了-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
yml配置
springboot2.0.0过后默认使用lettuce.pool而不使用jedis.pool
spring:
redis:
host: 192.168.150.101
password: 123321
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 1
max-wait: 300
测试
package com.gzdemo.redisdemo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
public class RedisTemplateTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
void testAdd() {
// String
redisTemplate.opsForValue().set("name","zhangsan");
// set
redisTemplate.opsForSet().add("myset","1");
// zset
redisTemplate.opsForZSet().add("myzset","stu1",10);
//hash
redisTemplate.opsForHash().put("myhash","stu1","1");
//list
redisTemplate.opsForList().leftPush("mylist","1");
}
}
运行单元测试,发现redis保存的这5个键值对出现乱码,原因是RedisTemplate默认使用的是Jdk序列化器。
二、StringRedisTemplate
RedisTemplate常用方法:https://blog.csdn.net/zzvar/article/details/118388897
先运行单元测试把新增的5个数据删掉
@Test
void testRemove() {
// String
redisTemplate.delete("name");
// set
redisTemplate.opsForSet().remove("myset","1");
// zset
redisTemplate.opsForZSet().remove("myzset","stu1");
//hash
redisTemplate.opsForHash().delete("myhash","stu1");
//list
redisTemplate.opsForList().rightPop("mylist");
}
将RedisTemplate换成StringRedisTemplate(使用了String序列化器)或者RedisTemplate<String,String>,不能是RedisTemplate<String,Object>,除非自己配置一个RedisTemplate<String,Object>
重新测试TestAdd
三、配置RedisTemplate<String,Object>(可选)
给RedisTemplate<String,Object>配置序列化器后,不会乱码。
可以直接用RedisTemplate<String,Object>传输一个对象(必须implements Serializable)
但通常不用这种方式,而是直接把对象转成json字符串保存在redis中
Redis配置
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.RedisSerializer;
@Configuration
public class RedisConfig {
/**
* RedisTemplate配置
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 创建RedisTemplate<String, Object>对象
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 设置RedisTemplate的连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 自定义序列化器
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);//序列化的类型为Object
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //序列化所有属性
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //设置这个过后,redis中的数据会携带该对象的类型,不方便读取
jackson2JsonRedisSerializer.setObjectMapper(om);
// key和hashKey的序列化器采用String
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
// value和hashValue的序列化器采用jackson2JsonRedisSerializer
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
return redisTemplate;
}
}
单元测试
//使用RedisTemplate<String,Object>需要配置一个RedisTemplate<String,Object>
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Test
public void Test1_Add(){
User u = User.builder()
.id(1000)
.name("zhangsan")
.phone("15730000001")
.build();
redisTemplate.opsForValue().set("user1", u);
}
@Test
public void Test1_Get(){
Object obj = redisTemplate.opsForValue().get("user1");
// 这里不能把Object强转为User类 否则会java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.gzdemo.redisdemo.domain.User
User user = JSONUtil.toBean(JSONUtil.toJsonStr(obj), User.class);
System.out.println(user);
}
四、StringRedisTemplate-以json字符串保存对象
通常用这种方式将某个对象保存在redis中,这种方式不需要类implements Serializable
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void Test2_Add(){
User u = User.builder()
.id(1000)
.name("zhangsan")
.phone("15730000001")
.build();
stringRedisTemplate.opsForValue().set("user2", JSONUtil.toJsonStr(u));
}
@Test
public void Test2_Get(){
String s = stringRedisTemplate.opsForValue().get("user2");
User user = JSONUtil.toBean(s, User.class);
System.out.println(user);
}
五、实际开发
实际开发中,在使用到缓存的地方,定义一个业务工具类。这里举个例子,基于LearningRecord实体类,比如
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.LocalDateTime;
...
@Component
@Slf4j
@RequiredArgsConstructor
public class LearningRecordCacheHandler {
private final StringRedisTemplate redisTemplate;
private final ILearningLessonService lessonService;
private final LearningRecordMapper recordMapper;
// 缓存前缀
private static final String LEARNING_RECORD_CACHE_PREFIX="learning:record:";
//1) 写入缓存
public void writeRecordCache(LearningRecord record){
log.info("缓存放入了消息:");
// 1.转成只有三个属性的对象
RecordCacheData cacheData = new RecordCacheData(record);
// 2. 转成json 字符串
String jsonData = JSONUtil.toJsonStr(cacheData);
// 3 拼接key learning:record:6688
String key =LEARNING_RECORD_CACHE_PREFIX+record.getLessonId();
// 4 存储缓存(覆盖)
redisTemplate.opsForHash().put(key,record.getSectionId().toString(),jsonData);
// 5 设置超时时间
redisTemplate.expire(key, Duration.ofSeconds(60));
}
//2) 读取缓存
public LearningRecord readRecordCache(Long lessonId,Long sectionId){
//1 拼接key learning:record:6688
String key =LEARNING_RECORD_CACHE_PREFIX+lessonId;
// 真正的是String
Object o = redisTemplate.opsForHash().get(key, sectionId.toString());
if(o==null){
return null;
}
// {id:1,moment:30,finshsend:false}
// 转成对象
LearningRecord record = JSONUtil.toBean(o.toString(), LearningRecord.class);
record.setLessonId(lessonId);
record.setSectionId(sectionId);
return record;
}
//3) 删除缓存
public void removeRecordCache(Long lessonId,Long sectionId){
//1 拼接key learning:record:6688
String key =LEARNING_RECORD_CACHE_PREFIX+lessonId;
redisTemplate.opsForHash().delete(key,sectionId.toString());
}
// 存储缓存的对象
@Data
@NoArgsConstructor
public class RecordCacheData{
private Long id;
private Boolean finished;
private Integer moment;
public RecordCacheData(LearningRecord record) {
this.id = record.getId();
this.finished = record.getFinished();
this.moment = record.getMoment();
}
}
}