当一个实体从两个不同的地方同时读取和更新时,这两个注释都可以用来防止java代码丢失更新。
它们为此目的是可互换的,只是依赖于不同的机制,我说得对吗?有人能解释两者之间的区别和可能的用例吗?
回答我自己的问题:是的,可以依靠@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
中是可能的
综上所述,这两种方法都可以解决这个特殊的问题。