当 Redis 碰上 @Transactional,有大坑,要注意!

最近项目的生产环境遇到一个奇怪的问题:

现象:每天早上客服人员在后台创建客服事件时,都会创建失败。当我们重启这个微服务后,后台就可以正常创建了客服事件了。到第二天早上又会创建失败,又得重启这个微服务才行。

初步排查:创建一个客服事件时,会用到 Redis 的递增操作来生成一个唯一的分布式 ID 作为事件 id。代码如下所示:

return redisTemplate.opsForValue().increment("count", 1);

而恰巧每天早上这个递增操作都会返回 null,进而导致后面的一系列逻辑出错,保存客服事件失败。当重启微服务后,这个递增操作又正常了。

那么排查的方向就是 Redis 的操作为什么会返回 null 了,以及为什么重启就又恢复正常了。

二、排查

根据上面的信息,我们先来看看 Redis 的自增操作在什么情况下会返回 null。

2.1 推测一

根据重启后就恢复正常,我们推测晚上执行了大量的 job,大量 Redis 连接未释放,当早上再来执行 Redis 操作时,执行失败。重启后,连接自动释放了。

但是其他有使用到 Redis 的业务功能又是正常的,所以推测一的方向有问题,排除。

2.2 推测二

可能是 Redis 事务造成的问题。这个推测的依据是根据下面的代码来排查的。

直接看 redisTemplate 递增的方法 increment,如下所示:

官方注释已经说明什么情况下会返回 null:

  • 当在 pipeline(管道)中使用这个 increment 方法时会返回 null。

  • 当在 transaction(事务)中使用这个 increment 方法时会返回 null。

事务提供了一种将多个命令打包,然后一次性、有序地执行机制.

多个命令会被入列到事务队列中,然后按先进先出(FIFO)的顺序执行。

事务在执行过程中不会被中断,当事务队列中的所有命令都被执行完毕之后,事务才会结束。(内容来自 Redis 设计与实现)

继续看代码,发现在操作 Redis 的 ServiceImpl 实现类的上面添加了一个 @Transactional 注解,推测是不是这个注解影响了 Redis 的操作结果。

2.3 验证推测二

如下面的表格所示,第二行中没有添加 Spring 的事务注解 @Transactional时,执行 Redis 的递增命令肯定是正常的,而接下来要验证的是表格中的第一行:加了 @Transactional 是否对 Redis 的命令有影响。

为了验证上面的

@RedisLock 和 @Transactional 是两个在代码中使用的注解。 @RedisLock 是一个自定义注解,用于在代码中实现分布式锁的功能。在引用和引用[2]的代码中,可以看到在执行某个方法之前先获取了一个分布式锁(redisLock.lock(id)),如果获取锁成功,则执行该方法的业务逻辑,然后释放锁(redisLock.unlock(id))。如果获取锁失败,则抛出异常表示当前操作无法进行。这样可以确保在分布式环境中同一时间只有一个线程能够执行被锁定的代码块。 @Transactional 是一个用于事务管理的注解。它可以用于类或方法上,用于标识需要被事务管理的代码块。在引用和引用的代码中,可以看到被 @Transactional 注解标记的方法表示该方法需要在事务中执行。在事务中,可以保证一系列的数据库操作要么全部成功提交,要么全部失败回滚。 需要注意的是,在引用中提到的一个问题是,当 @RedisLock 和 @Transactional 注解同时存在时,可能会导致分布式锁失效。因为事务的提交是在分布式锁释放之后进行的,这意味着在事务提交前,分布式锁已经被释放,可能导致其他线程获取到锁并同时执行被锁定的代码块。因此,在使用 @RedisLock 和 @Transactional 注解时需要特别注意这个问题,并确保在代码中正确处理分布式锁和事务的顺序。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【RedisRedis分布式锁的10个坑](https://blog.csdn.net/u011397981/article/details/130490197)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [java中锁与@Transactional同时使用导致锁失效的问题](https://blog.csdn.net/weixin_42134685/article/details/127090804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值