springBoot整合Redis


1,配置Redis配置类

package org.redislearn.configuration;

import java.lang.reflect.Method;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
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.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
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; @EnableCaching
@Configuration
public class RedisConfiguration extends CachingConfigurerSupport{
/*
* key的生成策略(根据目标对象,本例是service实现类,以及其中的方法,参数拼接成一个key)
* 可以根据业务需求更改策略
*/
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
/*
* 参数1:要操作的目标对象
* 参数2:要操作的方法
* 参数3:执行方法时的参数
*/
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sBuilder = new StringBuilder();
sBuilder.append(target.getClass().getName());
sBuilder.append(".");
sBuilder.append(method.getName()); //生成key
for(Object object:params){
sBuilder.append(".");
sBuilder.append(object.toString());
}
return sBuilder.toString();
}
};
}
/**
* redisTemplate相关配置 RedisTemplate操作Redis
* @param factory
* @return
*/
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
//设置工厂
template.setConnectionFactory(factory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
//(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =
new Jackson2JsonRedisSerializer<>(Object.class);
//创建对象映射
ObjectMapper mapper = new ObjectMapper();
//指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
mapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
//指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer
//等会抛出异常
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//
jackson2JsonRedisSerializer.setObjectMapper(mapper);
//字符串序列化器
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
//hash的key也采用String的方式
template.setHashKeySerializer(stringRedisSerializer);
//value采用jackson的方式
template.setValueSerializer(jackson2JsonRedisSerializer);
//hash的value也采用Jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet();
return template;
}
}

2,配置application.yml配置文件

server:
port: 8080
mybatis:
config-location: classpath:mybatis-config.xml
type-aliases-package: org.xxxx.entity
mapper-locations:
- classpath:mapper/*.xml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
username: root
password: 123456
redis:
host: 127.0.0.1
port: 6379
password:123456 # 生产环境中需要加上密码,不然数据及其不安全
jedis:
pool:
max-active: 10
max-idle: 5
min-idle: 2
max-wait: -1

3,操作Redis数据库

  • RedisTemplate<String,Object> :类似于Mybatis的SqlSession,用来操作数据库的对象
//在需要使用的地方利用spring注入RedisTemplate对象
@Autowired
private RedisTemplate<String,Object> redisTemplate;

4,使用Redis作缓存

  • 新建一个实体类

ps:存入redis的实体类数据需要实现序列化接口,不然会报org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; 至于原理,可以看看我看过的这篇文章了解一下

Redis为什么需要序列化https://www.zhihu.com/question/277363840/answer/392945240

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product implements Serializable {//redis need to serialize
private int pid;
private String pname;
private double price;
private int store;
private List<String> images;
private String detail;
}
  • (默认已经写好了mapper,service等接口和相关配置)

  • 在service实现类中的方法加注解

    • @Cacheable("xxx") //数据以xxx开头存入缓存
    • @CacheEvict(value = {"xxx","xxx"},allEntries = true) //清除缓存中的xxx开头的数据
    @Service
    public class ProductServiceImpl implements ProductService { @Autowired
    private ProductMapper productMapper; @Cacheable("findAll")
    @Override
    public List<Product> all() {
    return productMapper.all();
    } @Cacheable("findById")
    @Override
    public Product findProductByPid(int pid) {
    return productMapper.findProductByPid(pid);
    } //把跟这个id有关的数据都要删除,这里是"findAll"和"findById"
    @CacheEvict(value = {"findAll","findById"},allEntries = true)
    @Override
    public int deleteProductByPid(int pid) {
    return productMapper.deleteProductByPid(pid);
    }
    }
    • 这里的清除缓存的数据配置有问题,当执行删除方法的时候会将以"findAll","findById"开头的key的其他数据都清除掉,这样之后的查询又是从数据库查,性能再次下降

    解决方案:

    • 写一个工具类,生成对应的key,用来精准删除
    public class RedisUtil {
    public static String generate(String namespace,Object target, String method, Object... params) {
    StringBuilder sBuilder = new StringBuilder();
    sBuilder.append(namespace);
    sBuilder.append("::"); //自动生成的key会有双冒号
    sBuilder.append(target.getClass().getName());
    sBuilder.append(".");
    sBuilder.append(method); //生成key
    for(Object object:params){
    sBuilder.append(".");
    sBuilder.append(object.toString());
    }
    return sBuilder.toString();
    }
    }
    • 改进service实现类的方法
    //定义一个需要的命名空间
    private static final String NAMESPACE = "findProductByPid"; //删除指定的key
    @CacheEvict(value = "findAll",allEntries = true)
    @Override
    public int deleteProductByPid(int pid){
    //前缀 this method 参数
    String key = RedisUtil.generate(NAMESPACE,this,"findProductByPid",pid);
    System.out.println(key);
    //操作删除指令
    redisTemplate.delete(key);
    return productMapper.deleteProductByPid(pid);
    }
    • thinking :如果想要保留redis中的findAll的查询,那么可以在封装数据的时候把数据封装成hash,就不用list,通过对象名 的 filed删除这个数据,查询findAll的时候就还是从redis中来数据。但一般情况再从数据库查这一次影响不大,除非,删查非常频繁

至此,若有纰漏,望各位不吝赐教

最新文章

  1. win7系统下的飞秋发送文件失败问题
  2. JS 正则表达式详解
  3. windows下安装redis以及简单的事例
  4. proxy解析
  5. [Flex] ButtonBar系列——flex3 ButtonBar属性labelPlacement标签相对于指定图标的方向
  6. MyBatis学习总结_09_使用MyBatis Generator自动创建代码
  7. eclipse导入包的快捷键
  8. java三种工厂模式
  9. 补充一下我对 POJ 3273 的理解,这肯定是我一生写的最多的题解。。。
  10. 最常用的动态sql语句梳理——分享给使用Mybatis的小伙伴们!
  11. 注册DLL,Unregister DLL
  12. 一个可以拓展的垂直多级导航栏 Demo
  13. 阿里云ECS每天一件事D2:配置防火墙
  14. HDU4707:Pet(DFS)
  15. 【Java技术位】——代理模式及其事务包
  16. IDEA中 GIT与SVN版本控制插件的切换
  17. JSP面试题都在这里
  18. Python基础-Python的三元运算符和lambda表达式
  19. Gym102082 G-What Goes Up Must Come Down(树状数组)
  20. ubuntu14.06 Lts开启ssh服务

热门文章

  1. 深入剖析AQS
  2. Pipeline 脚本调用 mvn 命令失败
  3. 将XML转换为JSON并强制数组
  4. AJAX的GET请求、POST请求
  5. 如何安装vim自动补全插件YouCompleteMe(YCM)
  6. 关于时间格式 GMT,UTC,CST,ISO
  7. 安卓开发,Service 服务
  8. 一分钟开始持续集成之旅系列之:Java + GWT
  9. 内存节省机制C演示
  10. Python 简明教程 --- 19,Python 类与对象