首先整合Redis
1.导入依赖
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.20</version>
</dependency>
2.RedisConfig配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
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.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Duration;
@Configuration
public class RedisConfig {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
//Json序列化配置
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);
//String序列号配置
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key和hash的key都采用String的序列化配置
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
//value和hash的value采用Json的序列化配置
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
3.在Service实现类中进行缓存
由于我们请求的都是json字符串,所以使用StringRedisTemplate
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
}
由于我是初学Redis,于是使用一个分页查询的接口来练手。
首先说明,这里的分页查询是一对多查询,自己写了page方法以及sql语句,在整合Redis前通过mybatis-plus的分页功能进行。由于3.4.0之后的Mybatis-Plus,不再使用旧版本的PaginationInterceptor ,而是使用MMybatisPlusInterceptor。
可以使用以下配置类 :
@Configuration
@MapperScan("com.mu.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
原始的查询方法如下:
DeviceServiceImpl.java
//多表查询所有设备信息
@Override
public Result pageAllData(Integer pageNum, Integer pageSize, String devicename, Integer start, Integer end) {
IPage<DeviceDTO> page = new Page<>(pageNum,pageSize);
Result result = Result.success(deviceMapper.pageAllData(page,devicename,start,end));
System.out.println(result);
return result;
}
pageNum,pageSize : 分别为当前页数,以及每页显示多少数据。
devicename : 是按条件查询的设备名称。
start,end : 是按设备价格区间查询的参数。
初次整合Redis中时:
代码如下:
@Override
public Result pageAllData(Integer pageNum, Integer pageSize, String devicename, Integer start, Integer end) {
IPage<DeviceDTO> page = new Page<>(pageNum,pageSize);
//1.从缓存获取数据
String json = stringRedisTemplate.opsForValue().get(FILES_KEY);
IPage<DeviceDTO> deviceDTOIPage;
if (StrUtil.isBlank(json)) { //2.缓存取出来为空,就从数据库里面查
deviceDTOIPage = deviceMapper.pageAllData(page, devicename, start, end);
//3.从数据库取出来之后,4.再次缓存到redis
stringRedisTemplate.opsForValue().set(FILES_KEY, JSONUtil.toJsonStr((deviceDTOIPage)));
} else {
//5.如果缓存有
//从缓存中获取数据
deviceDTOIPage = JSONUtil.toBean(json, new TypeReference<IPage<DeviceDTO>>() {
}, true);
}
return Result.success(deviceDTOIPage);
}
第一次启动时,将redis里面的缓存清空,进入设备信息的模块时,第一次从数据库中查询数据,并装入Redis中缓存,页面显示数据,一切顺利。
可是当再次刷新,原本已经有缓存的情况下,页面数据直接清空,当打断点调试的时候,发现原来是当获取redis缓存中数据进行反序列化时候出现问题。
正常获取到json数据,但是转化为deviceDOTIPage后就变为空。
cn.hutool.core.convert.ConvertException报错
后来卡了一会儿,尝试了通过字符串转化,JSON对象转化,fastjson工具的使用都不行,后才才意识到IPage是一个接口类型,而json反序列化终究还是要转为一个实现类对象,那于是可以自定义一个分类类,实现IPage接口,根据json中的数据,可以自定义下面这些属性。
MyPage.java
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.mu.controller.dto.DeviceDTO;
import java.util.List;
public class MyPage implements IPage<DeviceDTO> {
private static final long serialVersionUID = 5760097915453738435L;
public static final int DEFAULT_PAGE_SIZE = 10;
/**
* 每页显示个数
*/
private int size;
/**
* 当前页数
*/
private int current;
/**
* 总页数
*/
private int total;
/**
* 总记录数
*/
private int totalCount;
/**
* 结果列表
*/
private List<DeviceDTO> records;
private List<OrderItem> orders;
@Override
public long getSize() {
return size;
}
@Override
public IPage<DeviceDTO> setSize(long size) {
return null;
}
public void setSize(int size) {
this.size = size;
}
@Override
public long getCurrent() {
return current;
}
@Override
public IPage<DeviceDTO> setCurrent(long current) {
return null;
}
public void setCurrent(int current) {
this.current = current;
}
@Override
public long getTotal() {
return total;
}
@Override
public IPage<DeviceDTO> setTotal(long total) {
return null;
}
public void setTotal(int total) {
this.total = total;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
@Override
public List<OrderItem> orders() {
return null;
}
@Override
public List<DeviceDTO> getRecords() {
return records;
}
@Override
public IPage<DeviceDTO> setRecords(List<DeviceDTO> records) {
this.records = records;
return null;
}
}
修改分页查询方法
//多表查询所有设备信息
@Override
public Result pageAllData(Integer pageNum, Integer pageSize, String devicename, Integer start, Integer end) {
IPage<DeviceDTO> page = new Page<>(pageNum,pageSize);
String jsonn = stringRedisTemplate.opsForValue().get(FILES_KEY);
JSONObject json = JSON.parseObject(jsonn);
IPage<DeviceDTO> deviceDTOIPage;
if (StrUtil.isBlank(jsonn)) { //2.缓存取出来为空,就从数据库里面查
deviceDTOIPage = deviceMapper.pageAllData(page, devicename, start, end);
//3.从数据库取出来之后,4.再次缓存到redis
stringRedisTemplate.opsForValue().set(FILES_KEY, JSONUtil.toJsonStr(deviceDTOIPage));
return Result.success(deviceDTOIPage);
} else {
//5.如果缓存有
//从缓存中获取数据
MyPage myPage = JSONUtil.toBean(jsonn, new TypeReference<MyPage>() {
}, false);
return Result.success(myPage);
}
}
最终,刷新可以显示出Redis缓存中的数据!
但是,目前还存在很多BUG。
首先就是点击第二页,竟然没有数据。在debug调试中,发现只返回第一页的数据,但是total是正确的,而records记录不全。可能自己对于redis的掌握不全面,后来意识到,当前key的缓存只存入了第一页,并且即使切换到了第二页,也因为json有数据,而没有再从数据库查询。
因此,一个简单的方法就是将每一页缓存一个key,当切换页数的时候自然会去数据库查询当前页的数据然后存入。
修改后代码如下:
//多表查询所有设备信息
// @Cacheable(value = "emp",key = "'findAll'")
@Override
public Result pageAllData(Integer pageNum, Integer pageSize, String devicename, Integer start, Integer end) {
IPage<DeviceDTO> page = new Page<>(pageNum,pageSize);
//1.从缓存获取数据
String key = "fenye" + pageNum;
this.key = key;
String jsonn = stringRedisTemplate.opsForValue().get(key);
JSONObject json = JSON.parseObject(jsonn);
IPage<DeviceDTO> deviceDTOIPage;
if (StrUtil.isBlank(jsonn)) { //2.缓存取出来为空,就从数据库里面查
deviceDTOIPage = deviceMapper.pageAllData(page, devicename, start, end);
//3.从数据库取出来之后,4.再次缓存到redis
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(deviceDTOIPage));
return Result.success(deviceDTOIPage);
} else {
//5.如果缓存有
//从缓存中获取数据
MyPage myPage = JSONUtil.toBean(jsonn, new TypeReference<MyPage>() {
}, false);
return Result.success(myPage);
}
}
如果要对当前某一条记录进行修改,就需要在修改后,删除当前缓存,下一次加载页面时,就会自动重新从数据库查出最新的数据。
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private String key;//得到当前页数的key
@Override
public Result saveOrUp(DeviceDTO deviceDTO) {
System.out.println(deviceDTO);
Device device = new Device();
if(deviceDTO.getOwnerName()!=""){
deviceDTO = owner(deviceDTO);//将设备拥有者与老师绑定
}
//通过deviceDto查询出对应的device
BeanUtil.copyProperties(deviceDTO,device,true);
System.out.println(device);
Result result = Result.success(saveOrUpdate(device));
photo(deviceDTO);
//删除当前页缓存
flushRedis(key);
return result;
}
private void flushRedis(String key) {
stringRedisTemplate.delete(key);
}
}
问题解决。
由于是练手,所以并不是很规范,希望也能给大家提供一点帮助!