提问者:小点点

JPA@版本vs@事务丢失更新


当一个实体从两个不同的地方同时读取和更新时,这两个注释都可以用来防止java代码丢失更新。

它们为此目的是可互换的,只是依赖于不同的机制,我说得对吗?有人能解释两者之间的区别和可能的用例吗?


共1个答案

匿名用户

回答我自己的问题:是的,可以依靠@Transactional来防止更新丢失以及@Version

我用以下场景进行了测试:
1.线程A选择一个实体E
2.线程B选择相同的实体
3.线程A以以下方式更新实体:增量字段E. a并保存实体。
4.线程B也这样做。
这种情况显然会导致称为“丢失更新”的问题,因为最终字段只会增加一次,而不是两次(符合预期)。

我希望将@Transactional放在执行“选择、更新和保存”操作的方法上可以防止这种情况。实际上,它成功了,但只有当我将@Transactional的隔离级别设置为REPEATABLE_READ时。之后,从第二个线程持久化实体时发生了异常。

我的假设是错误的,只是在我假设默认隔离级别(我用Postgres测试过)不可能丢失更新的部分。
事实并非如此!

我在深入研究这个问题时发现的好文章是来自Vlad Mihalcea的这篇文章:https://vladmihalcea.com/a-beginners-guide-to-database-locking-and-the-lost-update-phenomena/
他准确地解释了“丢失更新”问题和所有可能的解决方案,包括:
1.隔离级别=REPEATABLE_READ这在@Transactional
2.MVCC这在@Version中是可能的

综上所述,这两种方法都可以解决这个特殊的问题。