注意:spring事物与分布式锁同时使用问题


本文示例使用kotlin语言,java也大同小异

问题描述

A服务作为下游服务,就需要扛住上游服务的各种调用方式;某天上游调用的方式优化改进上线后,A服务的某接口开始出现重复数据处理问题,针对此问题当时最直观的猜想是redis分布式锁未起作用,比如redis服务故障或者什么原因?排查后发现是spring事物与锁使用不当造成的问题

一、spring事物与锁的错误使用示例

    @Transactional
    override fun doBusinessLogic(params: Any): Any? {
  
        ... 
        
        val lock = redisLock.createLock("xxxx_key")
        lock.lock()
        try {

           ...
           
        } finally {
            lock.unlock()
        }

这种写法的问题在于:当锁释放的时候事物还没有结束,此时另一个请求进入锁同步区域时读不到事物未提交的数据(这里数据库隔离级别采用的是读已提交)

二、改进

1.主要问题

  • 事物与锁的力度问题:锁的范围应该大于事物的范围
  • 考虑spring动态代理方法的生效条件:@Transactional注解事物是通过代理实现

2.正确示例

代码如下(示例):

@Component
class LockTransactionalSupport {

    @Transactional(rollbackFor = [Exception::class])
    fun <R> wrapperWithTransactional(action: () -> R): R {
        return action.invoke()
    }

}
@SpringBootTest
class XxxTest {

    @Autowired
    lateinit var lockTransactionalSupport: LockTransactionalSupport

    @Autowired
    lateinit var redisLock: RedisLock

    @Test
    fun testWrapperWithTransactional() {
        val lock = redisLock.createLock("my_lock_key")

        lock.lock()
        try {
            lockTransactionalSupport.wrapperWithTransactional {
            
                ...
                
                // do db save ops
                
                ...
                
                // throw err and rollback
                throw Exception("err.")
            }
        } finally {
            lock.unlock()
        }

    }
}
  • 将锁的范围放在事物的外层
  • 通过LockTransactionalSupport定义的函数式编程方式,用以保证@Transactional注解可以生效(对于代理方法必须要外部直接调用,才能走真正的代理逻辑)

当然如何在锁中去执行事务操作也有其他的实现方案,比如说编码的方式自己写 开启事物、提交事物或者回滚事物等


总结

  • 需要注意锁与事物同时使用的情况
  • 需要注意spring代理生效的条件



相关文章:

redis分布式锁使用注意事项

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柏油

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值