7

我正在尝试通过 Hibernate 3 对 Postgres 数据库使用 JPA 中的悲观锁定。我无法让锁超时 - 它似乎永远挂起。

这是一个例子:

EntityManagerFactory factory; 

// (initialise the factory )

EntityManager em1 = factory.createEntityManager();
EntityManager em2 = factory.createEntityManager();

// em1 gets a lock

EntityTransaction transaction1 = em1.getTransaction();
transaction1.begin();
MyObject object1 = em1.find( MyObject.class, 1, LockModeType.PESSIMISTIC_READ );

// em2 tries for a lock

Map<String,Object> timeoutProperties = new HashMap<String,Object>();
timeoutProperties.put("javax.persistence.lock.timeout", 5000);

EntityTransaction transaction2 = em2.getTransaction();
transaction2.begin();
MyObject object2 = em2.find( MyObject.class, 1, LockModeType.PESSIMISTIC_READ, timeoutProperties );

// After five seconds I expect em2 to bail out, but it never does.

transaction1.rollback();
transaction2.rollback();

据我了解,em2 应该尝试最多五秒钟(5000 毫秒)来获取锁,然后应该抛出异常。相反,代码会陷入僵局。

如果我在两个不同的线程中运行它,那么我会看到 thread2(带有 em2)在 thread1(em1)释放它时立即获得锁。所以锁定正在发生,只是永远不会超时。

我使用 PESSIMISTIC_WRITE 和任何超时值(2ms、0ms 'NO WAIT')等都得到了相同的效果。

我正在使用 Hibernate 3.6.10 Final(最新的 Hibernate 3 版本)和 Postgres jdbc 驱动程序 9.2-1003.jdbc4(最新的驱动程序)。我正在针对 Postgres 8.4 数据库运行。

我发现的所有文档都表明这应该可行。有任何想法吗?

谢谢,阿拉斯泰尔

4

3 回答 3

9

Postgres SELECT for update 语法仅提供在无法立即获得锁时不等待的选项。请参阅 postgres 文档。

要防止操作等待其他事务提交,请使用 NOWAIT 选项。使用 NOWAIT,如果无法立即锁定选定行,则语句将报告错误,而不是等待。请注意,NOWAIT 仅适用于行级锁——所需的 ROW SHARE 表级锁仍以普通方式获取(参见第 13 章)。如果您需要在不等待的情况下获取表级锁,您可以先使用 LOCK 和 NOWAIT 选项。

在使用 postgres 时,我观察到任何超过 0 的超时值都会导致休眠问题SELECT FOR UPDATE,但是当超时为 0 时,它会发出SELECT FOR UPDATE NO WAIT

于 2013-11-08T03:06:42.577 回答
0

把它放在你的 persistence.xml 中:

<property name="javax.persistence.lock.timeout" value="0"/>

或者在调用第一个锁之前设置属性。

于 2013-10-30T17:21:20.040 回答
0

javax.persistence.lock.timeout 在如下提供时也不适合我

@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout",value = "15000")})

但后来我尝试了其他有效的方法。现在我使用实体管理器配置我的 hbernate,而不是使用 @Repository 和 CrudRepository。使用 createQuery 以及锁定和设置锁定超时。并且此配置按预期工作。我有两个并行运行的事务,并试图在数据库中锁定完全相同的行。第一个事务能够获得 WRITE 锁并在释放锁之前持有锁大约 10 秒。同时,第二个事务尝试在同一行获取锁,但由于 javax.persistence.lock.timeout 设置为 15 秒,它等待锁被释放然后获取自己的锁。因此使流程序列化。

@Component
public class Repository {

    @PersistenceContext
    private EntityManager em;

    public Optional<Cache> getById(int id){
        List<Cache> list = em.createQuery("select c from Cache c where c.id = ?1")
                            .setParameter(1, id)
                            .setHint("javax.persistence.lock.timeout", 15000)
                            .setLockMode(LockModeType.PESSIMISTIC_WRITE)
                            .getResultList();


        return Optional.ofNullable(list.get(0));
    }

    public void save(Cache cache) {
        cache = em.find(Cache.class, cache.getId());
        em.merge(cache);
    }
}
于 2019-11-24T20:12:32.303 回答