我在JPA中有一个简单的一对多关系。为了讨论的缘故,假设我的实体是Person和Phone,一个Person可以有多个Phone(数字)。JPA:锁定相关对象(eclipselink)
两个对象都可以独立更新,并且我具有很高的并发性。我需要对两个对象实施悲观锁定(无论如何,这是我的假设)。
所以,在我的代码,我这样做,
em.getTransaction().begin();
Person p = em.find(Person.class, id, LockModeType.PESSIMISTIC_WRITE);
...
,同样的电话,
em.getTransaction().begin();
Phone ph = em.find(Phone.class, id, LockModeType.PESSIMISTIC_WRITE);
...
注意,在个人的交易中,因电话对象可以被更新,反之亦然。用例是lastModified标志。更新Phone将更新拥有Person中的lastModified时间戳,相反,更新Person中的lastModified时间戳记会更新Phone中的lastModified标志(这是通过实体监听器完成的)。我意识到这个用例是有点人为的,但是试图忽略它。
上述代码导致死锁。
INFO: [EL Warning]: 2011-06-30 08:41:52.65--ServerSession(122902)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLTransactionRollbackException: A lock could not be obtained within the time requested
Error Code: 30000
我在这个时候假设是,个人的交易伸手去抓人A上的锁,然后试图在同一时间以获取电话1.锁,电话交易抓起锁电话1,击败Person事务,然后尝试为Person A死锁获取锁定。
这只是一个猜测,它基于对事务如何工作的天真理解,并且基本上没有关于JPA中对象锁定如何工作的知识。我会认为该对象和它的依赖项被原子锁定...这就是需要发生的工作。
有什么想法?
解决这个问题的一个想法是我忘记了在同一事务中更新依赖对象。而是在第一次完成更新依赖对象后打开一个新事务。
我会尝试你的建议。我尝试使用乐观锁,导致OptmisitcLockExceptions。在这种情况下,我无法找到一个好的模式。从WS返回500给调用者?即使有延迟,我也希望事情能够为客户服务。 –
也不清楚如何以正确的顺序抓住锁。例如,当我更新手机时,我不知道该人,直到我查询它。所以我应该用一个读锁来查询,然后开始一个新的事务,并按照正确的顺序在那里获取锁? –
,真正的问题是:JPA以什么顺序抓住锁,以及如何影响该锁? –