2011-06-30 29 views
0

我在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中对象锁定如何工作的知识。我会认为该对象和它的依赖项被原子锁定...这就是需要发生的工作。

有什么想法?

解决这个问题的一个想法是我忘记了在同一事务中更新依赖对象。而是在第一次完成更新依赖对象后打开一个新事务。

回答

2

这似乎很奇怪,我说你,同时

  • 需要悲观锁(这似乎意味着,你真的不想两个事务更新人/在同一时间电话)
  • 就可以通过在两个单独的交易

做一个操作反正牺牲数据的一致性,如果你真的需要去与悲观锁,确保锁被以相同的顺序总是要求(人然后拨打电话,然后再拨打电话erson,但不是两者)。这应该可以防止你面临的那种僵局。

+0

我会尝试你的建议。我尝试使用乐观锁,导致OptmisitcLockExceptions。在这种情况下,我无法找到一个好的模式。从WS返回500给调用者?即使有延迟,我也希望事情能够为客户服务。 –

+0

也不清楚如何以正确的顺序抓住锁。例如,当我更新手机时,我不知道该人,直到我查询它。所以我应该用一个读锁来查询,然后开始一个新的事务,并按照正确的顺序在那里获取锁? –

+0

,真正的问题是:JPA以什么顺序抓住锁,以及如何影响该锁? –