如何在 postgres 中设置锁定超时 - 休眠

2022-09-04 02:57:39

我正在尝试为我正在处理的行设置一个 Lock,直到下一个提交:

entityManager.createQuery("SELECT value from Table where id=:id")
            .setParameter("id", "123")
            .setLockMode(LockModeType.PESSIMISTIC_WRITE)
            .setHint("javax.persistence.lock.timeout", 10000)
            .getSingleResult();

我认为应该发生的是,如果两个线程将尝试同时写入数据库,则一个线程将先于另一个线程到达更新操作,则第二个线程应等待10秒,然后抛出悲观LockException

但相反,线程会挂起,直到另一个线程完成,而不管超时集如何。

看看这个例子:

database.createTransaction(transaction -> {
    // Execute the first request to the db, and lock the table
    requestAndLock(transaction);

    // open another transaction, and execute the second request in
    // a different transaction
    database.createTransaction(secondTransaction -> {
        requestAndLock(secondTransaction);
    });

    transaction.commit();
});

我预计在第二个请求中,事务将等到超时集,然后抛出悲观锁例外,但它永远处于死锁状态。

休眠以这种方式生成我对数据库的请求:

SELECT value from Table where id=123 FOR UPDATE

在这个答案中,我看到只允许将超时设置为0,但不可能以这种方式设置超时。PostgresSELECT FOR UPDATE NO WAIT

有没有其他方法可以与 ?也许这种方式以某种方式被推荐?Hibernate / JPA


答案 1

休眠支持一堆查询提示。您使用的那个设置查询的超时,而不是悲观锁的超时。查询和锁彼此独立,您需要使用如下所示的提示。

但在你这样做之前,请注意,Hibernate本身不会处理超时。它仅将其发送到数据库,并且取决于数据库,以及它是否以及如何应用它。

要为悲观锁设置超时,需要改用提示。下面是一个示例:javax.persistence.lock.timeout

entityManager.createQuery("SELECT value from Table where id=:id")
        .setParameter("id", "123")
        .setLockMode(LockModeType.PESSIMISTIC_WRITE)
        .setHint("javax.persistence.lock.timeout", 10000)
        .getSingleResult();

答案 2

我想你可以试试

SET LOCAL lock_timeout = '10s';
SELECT ....;

我怀疑Hibernate支持这种开箱即用。你可以尝试找到一种方法来扩展它,不确定它是否值得。因为我想在postges数据库(即mvcc)上使用锁并不是最聪明的选择。

您还可以从代码中执行并延迟重试几次。NO WAIT


推荐