注意:spring事物与分布式锁同时使用问题
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结前言提示:这里可以添加本文要记录的大概内容:例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。提示:以下是本篇文章正文内容,下面案例可供参考一、pandas是什么?示例:pandas 是基于N
·
本文示例使用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代理生效的条件
相关文章:

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)