文章插图
下面是针对这段代码的解释,简单来说就是开启事务,将 Redis 命令顺序放到一个队列中,然后最后一起执行,且保证原子性 。
setEnableTransactionSupport
表示是否开启事务支持,默认不开启 。文章插图
难道开启了 Redis 事务,还能影响 Spring 事务中的 Redis 操作?2.5 验证推测三如下表,序号 3 和 序号 4 的场景都是开启了 Redis 的事务支持,两个场景的区别是是否加了 @Transactional 注解 。
文章插图
为了验证上面的场景,我们来做个实验:
- 先开启 Redis 事务支持,然后执行 Redis 的事务命令 multi和 exec。
- 验证场景 3:在 @Transactional 注解的方法中执行 Redis 的递增操作 。
- 验证场景 4:在非 @Transactional 注解的方法中执行 Redis 的递增操作
文章插图
如下图所示,设置成功了 。
文章插图
2.5.2 @Transactional 中执行 Redis 命令接下来在标注有 @Transactional 注解的方法中执行 Redis 的递增操作 。
文章插图
多次执行这个命令返回的结果都是 null,这不就正好重现了!
文章插图
再来看 Redis 中 count 的值,发现每执行一次 API 请求调用,都会递增 1,所以虽然命令返回的是 null,但最后 Redis 中存放的还是递增后的结果 。
文章插图
文章插图
接下来我们验证下场景 4,先执行 Redis 事务操作,然后在不添加 @Transactional 注解的方法中执行 Redis 递增操作 。
文章插图
用 Postman 调用这个接口后 , 正常返回自增后的结果,并不是返回 null 。说明在非 @Transactional 中执行 Redis 操作并没有受到 Redis 事务的影响 。
文章插图
四个场景的结论如下所示,只有第三个场景下,Redis 的递增操作才会返回 null 。
文章插图
问题原因找到了,说明 RedisTemplete 开启了 Redis 事务支持后,在 @Transactional 中执行的 Redis 命令也会被认为是在 Redis 事务中执行的 , 要执行的递增命令会被放到队列中,不会立即返回执行后的结果,返回的是一个 null,需要等待事务提交时,队列中的命令才会顺序执行,最后 Redis 数据库的键值才会递增 。
三、源码解析那我们就看下为什么开启了 Redis 事务支持,效果就不一样了 。
找到 Redis 执行命令的核心方法,execute 方法 。
文章插图
然后一步一步点进去看,关键代码就是 211 行到 216 行 , 有一个逻辑判断,当开启了 Redis 事务支持后,就会去绑定一个连接(
bindConnection
) , 否则就去获取新的 Redis 连接(getConnection
) 。这里我们是开启了的,所以再到 bindConnection
方法中查看如何绑定连接的 。文章插图
接着往下看,关键代码如下所示,当开启了 Redis 事务支持 , 且添加了 @Transactional 注解时,就会执行 Redis 的 mutil 命令 。
关键代码:conn.multi();
文章插图
Redis Multi 命令用于标记一个事务块的开始,事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行 。
真相大白,开启 Redis 事务支持 + @Transactional 注解后,最后其实是标记了一个 Redis 事务块,后续的操作命令是在这个事务块中执行的 。比如下面的的递增命令并不会返回递增后的结果,而是返回 null 。
推荐阅读
- 一 Redis数据结构-Redis的数据存储及String类型的实现
- Redis Cluster 原理说的头头是道,这些配置不懂就是纸上谈兵
- 抛砖系列之redis监控命令
- SpringCloud整合分布式事务Seata 1.4.1 支持微服务全局异常拦截
- 记一次 .NET 某娱乐聊天流平台 CPU 爆高分析
- Redis 01: 非关系型数据库 + 配置Redis
- Redis 02: redis基础知识 + 5种数据结构 + 基础操作命令
- 1 Redis—问题
- 之四 2流高手速成记:SpringBoot整合redis及mongodb
- 记录一次成功反混淆脱壳及抓包激活app全过程