JPA乐观锁定

时间:2015-07-23 11:26:23

标签: java jpa jpa-2.0 optimistic-locking

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

BUT
This docu说:" JPA乐观锁定允许任何人读取和更新实体,但是在提交时进行版本检查,如果在读取实体后数据库中的版本已更新,则抛出异常。 "
根据这个desc,应该抛出异常,因为版本检查是在提交时进行的(我假设它们是指每次提交,包括读取后的提交)。

我想要实现所描述的场景不应该抛出任何Concurency Exception,如果线程A返回的用户列表不是最新的,则没有问题。那么使用乐观锁定是否正确,或者不使用哪种LockType?

2 个答案:

答案 0 :(得分:2)

你给的两个链接说同样的话。如果在TransactionA中更新实体,并且由于TransactionA读取实体,它已在TransactionB中在DB中进行了修改,那么将抛出OptimisticLockException。

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

你会希望在这种情况下抛出异常,否则只有一个更新会成功 - 最后一个提交将简单地覆盖先前的提交 - 但哪一个将是最后一个有点不确定 - 有时有时是线程threadB和DB内容实际上并不像预期的那样。所以锁定可以防止这种不良行为。

如果您的应用程序事务经常与数据冲突,请考虑使用https://blogs.oracle.com/carolmcdonald/entry/jpa_2_0_concurrency_and中描述的悲观锁定

答案 1 :(得分:1)

乐观锁定很容易理解:

每个实体都有一个timestamp / version numer属性。

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

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

悲观锁定是一个可扩展性问题,因为它只允许在给定资源上一次访问一次更新(因此其他 - 不是只读 - 访问被阻止),但它可以避免操作失败。如果您无法承担松散操作的责任,那么如果可扩展性不是问题,那么就要悲观,否则在业务级别处理并发缓解。