目录
一、核心流程
- 引入依赖
- 创建RedisConfig配置文件
- 使用Redis缓存数据
配置Redis的序列化是为了解决程序中的数据转化成Redis二进制数据后无法直观查看数据信息的问题。
二、代码实战
2.1 引入依赖
spring-boot-starter-data-redis默认会使用lettuce,本次使用的是Jedis,所以依赖中我们要屏蔽掉lettuce而改用jedis。
Springboot会帮我们自动装配Redis,自动生成RedisConnectionFactory、RedisTemplate、StringRedisTemplate等常用的Redis对象。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.7.5</version> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
在spring-data-redis中,RedisConnection通过RedisConnectionFactory创建,Spring为了简化以上操作,做出了简化,并诞生了RedisTemplate
2.2 创建RedisConfig配置文件
因为Redis的数据以二进制的方式存储,与Java数据不相同,所以直接存入Java数据到Redis中会导致你在使用RedisCli查看数据时,是我们无法看懂的二进制序列化数据,为了解决这个问题,我们需要对Redis配置序列化的方式。
package com.example.demo.config.redis; /** * @Author : HuangJiajian * @create 2022/10/24 9:07 */ @Configuration public class RedisConfig { /** * @Author HJJ * @Date 2022-12-30 15:49 * @Params * @Return * @Description 注入CacheManager */ @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { return RedisCacheManager.builder(factory) .cacheDefaults(defaultCacheConfig()) .transactionAware() .build(); } /** * @Author HJJ * @Date 2022-12-30 15:48 * @Params * @Return * @Description 配置通过@Cacheable注解缓存的序列化方式以及过期时间 */ private RedisCacheConfiguration defaultCacheConfig() { Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY); serializer.setObjectMapper(mapper); return RedisCacheConfiguration.defaultCacheConfig() // 20秒过期 .entryTtl(Duration.ofSeconds(20)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer)) .disableCachingNullValues(); } }
2.3 使用Redis缓存数据
在Controller层中,使用@Cacheable注解来缓存return的数据。
@Cacheable(value, key)中,value是属性名称,key是标识,在RedisCli中应该通过
get value::key
的形式读取数据,如get User::Jack
、get User::John
package com.example.demo.controller; /** * @Author : HuangJiajian * @create 2022/12/2 10:59 */ @RestController @RequestMapping("/cache") public class TestRedis { @Autowired private StringRedisTemplate stringRedisTemplate; @GetMapping("/str") @Cacheable(key = "#str", value = "Str") public String cacheStr(String str) { System.out.println("缓存str(第二次同参数时,不应该出现这一打印信息):" + str); return cache; } @GetMapping("/user") @Cacheable(key = "#username", value = "User") public AjaxResult cacheUser(String username) { UserEntity userEntity = new UserEntity(u, "123456"); System.out.println("缓存username(第二次同参数时,不应该出现这一打印信息):" + username); return new AjaxResult(AjaxResult.CODE.SUCCESS, "success", userEntity); } }
验证缓存
发送发送2次GET请求/cache/str
,参数都是?str=value1
,结果如下:
第一次请求:
控制台打印出”缓存str(第二次同参数时,不应该出现这一打印信息):value1“
浏览器获取到数据“value1”
RedisCli运行
get Str::value1
打印出”value1″第二次请求:
控制台不打印
浏览器获取到数据“value1”
RedisCli运行
get Str::value1
打印出”value1″
三、拓展知识
3.1 Redis事务
事务处理简单来讲就是“要么是0,要么是1”。常见于电商系统,如商品在用户提交的订单后库存便减少,但若用户取消支付或支付失败,就需要将库存数据回滚。Redis也具有部分事务处理的功能。
Redis的事务处理包含三个部分:watch(监控)…multi(开始)…exec(执行)
@GetMapping("/multi") public String testMulti(){ stringRedisTemplate.opsForValue().set("key1", "value1"); List list = (List) stringRedisTemplate.execute(new SessionCallback<Object>() { @Override public Object execute(RedisOperations ops) throws DataAccessException { ops.watch("key1"); ops.multi(); ops.opsForValue().set("key2", "value2"); // 还未执行事务,所以数据是空的 System.out.println(ops.opsForValue().get("key2")); // null // 情况1:在multi和exec之间打断点,然后使用reids-cli修改key1的值,exec之后Redis会监听到key1已经发生改变,故会回滚事务。 // 情况2:key1增操作错误,但Redis仅存在队列中,直到exec时才会报错,应避免 // ops.opsForValue().increment("key1", 1); ops.exec(); return null; } }); System.out.println(list); return "end"; }
四、问题记录
4.1 @Cacheable注解失效
@Cacheable的原理是SpringAOP,很多@Cacheable失效的原因都是因为RedisConfig的初始化在其使用位置之后,所以无法执行AOP拦截,导致@Cacheable注解失效。这个可以通过使用@Autowired StringRedisTemplate stringRedisTemplate;
实现Redis缓存,但这样并不会用上RedisConfig中的配置,所以需要在函数中自己配置序列化方式和过期时间等。
还有一种是@Cacheable方法A(),然后使用方法B()去调用方法A,我知道你想要让B调用A时,返回A在Redis中的缓存数据,但这样也是无法做到的。
参考文献
- 10分钟拿下 HashMap
- 深入浅出Spring Boot 2.x
- RedisTemplate配置的jackson.ObjectMapper里的一个enableDefaultTyping方法过期解决
转自:
https://blog.csdn.net/qq_41297145/article/details/128497859