JPA:锁定依赖对象(eclipselink)



我在JPA中有一个简单的一对多关系。为了便于讨论,假设我的实体是个人和电话,其中一个人可以有许多电话号码。

这两个对象都可以独立更新,而且我具有高并发性。我需要在这两个对象上实现悲观锁定(这是我的假设(。

所以,在我的代码中,我做了一些类似的事情

            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);
            ...

请注意,在Person事务中,依赖的Phone对象可能会更新,反之亦然。用例是一个lastModified标志。更新Phone会更新拥有者中的lastModified时间戳,相反,更新Person中的lastModified时间戳会更新Phone中的lastModify标志(这是通过实体侦听器完成的(。我意识到这个用例有点做作,但尽量忽略这一点。

上面的代码导致死锁。

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

我现在的假设是,Person交易为Person a获取了一个锁,然后试图为Phone 1获取一个锁。与此同时,Phone事务为Phone 1获取锁,击败Person事务,然后尝试为Person a获取锁。死锁。

这只是一个猜测,它基于对事务如何工作的天真理解,而对JPA中对象锁定如何工作基本上一无所知。我会认为对象及其从属对象被原子锁定。。。这就是需要发生的事情。

有什么想法吗?

解决这个问题的一个想法,我将尝试,就是忘记更新同一事务中的依赖对象。相反,在第一个事务完成后打开一个新事务来更新依赖对象。

我觉得很奇怪,你同时也是

  • 需要悲观锁(这似乎意味着你真的不希望两个交易同时更新个人/手机(
  • 准备通过在两个独立事务中执行单个操作来牺牲数据一致性

不管怎样,如果你真的需要使用悲观锁,请确保总是以相同的顺序请求锁(人然后是电话,或者电话然后是人,但不是两者都有(。这应该可以防止您面临的那种僵局。

最新更新