当前位置: 代码迷 >> java >> JPA乐观锁定
  详细解决方案

JPA乐观锁定

热度:13   发布时间:2023-08-02 10:47:51.0

我在理解OPTIMISTIC LockMode时遇到了一些麻烦。
让我们考虑以下情况:“线程A创建一个事务并从表USERS中读取所有用户的列表。线程B更新表USERS中的一个用户。线程B提交。线程A提交”。
假设我正在使用OPTIMISTIC锁定。 在这种情况下,第二次提交会导致引发OptimisticLockException吗?
因为根据 :“在提交(和刷新)期间,ObjectDB会检查每个必须更新或删除的数据库对象,并将该对象在数据库中的版本号与正在更新的内存中对象的版本号进行比较。如果版本号不匹配,则事务失败,并引发OptimisticLockException。
不应抛出任何异常,因为仅针对那些必须更新或删除的实体检查版本号。


是:“ JPA乐观锁定允许任何人读取和更新实体,但是在提交后进行版本检查,如果自读取实体以来在数据库中更新了版本,则会引发异常。”
根据这个说明,应该抛出异常,因为版本检查是在提交时进行的(我认为它们意味着每个提交,包括读取后的提交)。

我想实现所描述的方案不应引发任何Concurency Exception,如果线程A返回的不是最近用户列表,这没问题。 那么使用开放式锁是正确的吗?或者如果不宜使用哪种LockType?

您提供的两个链接表示相同的内容。 如果一个实体正在TransactionA中进行更新,并且自从TransactionA读取该实体以来已由TransactionB在数据库中对其进行了修改,则将引发OptimisticLockException。

在您的情况下,您正在检索threadA中所有用户的列表, 但仅更新了一个 仅当相同实体在线程b中更改并提交(尝试)时,您才会获得OptimisticLockException。

您可能希望在这种情况下引发异常,否则,只有一个更新会成功-提交的最后一个更新将仅覆盖先前的提交-但将成为最后一个的更新有点不确定-有时threadA有时threadB且数据库内容确实不是预期的。 因此,锁定可以防止这种不良行为。

如果您的应用程序交易经常与数据冲突,请考虑使用悲观锁定,也请参见

乐观锁很容易理解:

每个实体都有一个时间戳/版本号属性。

每次更新实体时,时间戳/版本号也会更新。 更新实体时,如果您在持久层(数据库)中加载的实际时间戳已经更改,则首先要读取它,然后会引发OptimisticLockException,否则会与新的时间戳/版本号一起更新。

如果您没有并发更新的风险,那么就不应该使用任何锁定机制,即使是乐观的锁定机制也会对性能产生影响(您必须在更新实体之前检查时间戳记)。

悲观锁定是一个可伸缩性问题,因为它一次只允许对给定资源进行一次访问以进行更新(因此阻止了其他(非只读)访问),但避免了操作失败。 如果您不承担失去可操作性的麻烦,那么在可伸缩性不是问题的情况下,请不要悲观,否则应在业务级别处理并发缓解。

  相关解决方案