【问题标题】:JPA: locking dependent objects (eclipselink)JPA:锁定依赖对象(eclipselink)
【发布时间】:2011-06-30 15:47:55
【问题描述】:

我在 JPA 中有一个简单的一对多关系。为了便于讨论,假设我的实体是 Person 和 Phone,其中一个 Person 可以有多个 Phone(数字)。

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

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

            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 会更新所属 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

我此时的假设是,Person 事务为 Person A 抢了一个锁,然后试图为 Phone 1 获取一个锁。同时,Phone 事务为 Phone 1 抢了一个锁,击败了 Person 事务,然后尝试为人 A 获取锁。死锁。

这只是一个猜测,它基于对事务如何工作的幼稚理解,以及对 JPA 中对象锁定如何工作的基本零知识。我会认为该对象及其依赖项被原子锁定......这就是为此工作所需要的。

有什么想法吗?

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

【问题讨论】:

    标签: java jpa transactions eclipselink


    【解决方案1】:

    我觉得你同时也很奇怪

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

    无论如何,如果您真的需要使用悲观锁,请确保始终以相同的顺序请求锁(人然后电话,或电话然后人,但不能同时使用)。这应该可以防止您面临的那种僵局。

    【讨论】:

    • 我会试试你的建议。我尝试使用乐观锁,这导致了 OptmisitcLockExceptions。在这种情况下,我找不到我应该做什么的好模式。从 WS 向调用者返回 500?我只想为客户工作,即使有延误。
    • 另外,目前还不清楚如何以正确的顺序获取锁。例如,当我更新电话时,我不知道这个人,直到我查询它。所以我应该用读锁查询来获取它,然后开始一个新事务,并在那里以正确的顺序获取锁吗?
    • 真正的问题是:JPA 获取锁的顺序是什么,我如何影响它?
    • 无论解决方案如何,如果您有多个用户试图同时更新相同的数据,您将不得不处理异常。阅读weblogs.java.net/blog/2009/07/30/jpa-20-concurrency-and-lockingdownload.oracle.com/javaee/6/tutorial/doc/gkjiu.html(特别是要知道如何设置超时)。此外,无论解决方案如何:一切都应该在单个事务中完成。正如第一个教程所示,您可以在不加锁的情况下阅读,然后显式锁定,以确保始终使用相同的顺序。当您告诉它锁定时,JPA 会抓住锁。
    • 直接的问题似乎是锁定顺序。我没有锁定 em.find(),而是以明确定义的顺序手动锁定,无论它是父对象还是子对象。
    猜你喜欢
    • 2012-02-03
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 1970-01-01
    • 2020-08-06
    • 2015-11-06
    • 2013-12-03
    • 1970-01-01
    相关资源
    最近更新 更多