我正在尝试为我正在处理的行设置一个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秒,然后抛出PessimisticLockException
。
但是,不管超时设置如何,线程都会挂起,直到另一个线程完成。
看看这个例子:
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();
});
我预计在第二个请求中,事务将等待,直到超时设置,然后抛出PessimisticLockException
,但它却永远死锁。
Hibernate以这种方式生成我对数据库的请求:
SELECT value from Table where id=123 FOR UPDATE
在这个answer中,我看到Postgres
只允许将超时设置为0的SELECT FOR UPDATE NO WAIT
,但不能以这种方式设置超时。
有没有其他方法可以和Hibernate / JPA
一起使用?也许以某种方式推荐了this way?
发布于 2018-08-17 19:36:20
Hibernate支持bunch of query hints。您正在使用的锁为查询设置超时,而不是为悲观锁设置超时。查询和锁是相互独立的,您需要使用下面显示的提示。
但在此之前,请注意,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();
发布于 2018-08-15 18:27:37
我觉得你可以试试
SET LOCAL lock_timeout = '10s';
SELECT ....;
我怀疑Hibernate是否支持这种开箱即用的方式。你可以试着找一种方法来扩展它,但不确定它是否值得。因为我认为在postges数据库(即mvcc)上使用锁不是最明智的选择。
您还可以在代码中执行NO WAIT
和延迟重试多次。
发布于 2018-08-15 04:32:27
有一个lock_timeout
参数,它可以执行您想要的操作。
您可以按用户或按数据库在postgresql.conf
中或使用ALTER ROLE
或ALTER DATABASE
设置它。
https://stackoverflow.com/questions/51845853
复制相似问题