java - Spring JPA,结合@Lock 和@Transactional 来同步并发数据库访问
问题描述
我正在实现一个工作流,其中一个实体可以由于两个并发事件而被更新:
public void onSomethingHappened(int entityId)
entity = repository.findById(entityId)
if (entity == null) {
entity = createNew()
}
entity.doSomething()
repository.save(entity)
public void onSomethingElseHappened(int entityId)
entity = repository.findById(entityId)
if (entity == null) {
entity = createNew()
}
entity.doSomethingElse()
repository.save(entity)
所以我想要防止这种情况发生,例如,onSomethingHappened
在另一个方法正在执行时正好读取数据库,因为这将导致在onSomethingElseHappened
执行相同操作时创建实体的实例,从而产生脏读
我想到的第一件事是用悲观锁定来处理这种情况,并使这两种方法都 @Transactional 并设置 @Lock on repository.findById()
。我的期望是两个事务中的一个将获取锁并在方法执行结束时释放它,所以另一个方法在另一个方法保存实体之前不会完成读取,这样读取就会产生非空结果
但是,文档似乎没有提供有关它的更多信息
另一种选择可能是使用乐观并发控制,在 Entity 中使用 @Version 注释字段并在它们引发OptimisticLockException
...but时重试这两个操作之一
- 我不确定这在自动生成实体 ID 时是否有效,因为这两种方法都会创建两个不同实体的初始版本。也许我应该以某种方式使用 generatedId 来计算版本号?
- 其他限制可能会导致最好不要采用这种方法
那么,悲观锁定方式可行吗?如果不是,如何确保乐观锁定在插入行的情况下有效?
解决方案
推荐阅读
- reactjs - Firebase、React、高阶函数
- android - 如何确定上一个会话中的线程当前是否正在运行
- java - Keycloak:引用第三方库的自定义事件监听器
- java - Hibernate 如何使用 InheritanceType.JOINED 区分对象类型
- swift - 按下 tableViewCell 时将数据发送回之前的 View Controller
- node.js - 环境变量不适用于 React 和变量 [节点]
- c# - .NET 版本程序集是用(目标版本)编译的
- postgresql - 尝试在 centos 7 上安装 pgagent 时出现 Boost_MISSING_DEPENDENCIES
- c++11 - /usr/bin/ld: 找不到 -lboost_thread-lpthread
- ios - 如何发送带有媒体附件的 ios 推送通知(Azure Notif Hub)?