如何使用 EntityManager 通过 id 查找实体而不在一个查询中命中缓存?

How to use EntityManager to find an entity by id without hitting cache in one query?

我有一个代码的关键部分,我需要使用悲观锁通过 id 读取和锁定实体。

这部分代码现在看起来像这样:

MyEntity entity = entityManager.find(MyEntity.class, key);
entityManager.refresh(entity, LockModeType.PESSIMISTIC_WRITE);

它工作正常,但据我所知,如果休眠缓存中没有实体,我们将对数据库使用 2 个读取事务。第一个事务通过 id 查找实体,另一个事务刷新和锁定实体。 在这种情况下是否可以只使用一个事务?

我会想象这样的事情:

boolean skipCache = true;
MyEntity entity = entityManager.find(MyEntity.class, key, 
    LockModeType.PESSIMISTIC_WRITE, skipCache);

但是没有skipCache这样的参数。是否有另一种方法可以使用 EntityManager 直接从数据库中按 ID 读取实体?

更新:

如果实体存在于缓存中,则此查询将命中一级缓存。因此,它可能 return 过时的数据,这就是为什么它不适合任何读取都应该被阻止的关键部分:

MyEntity entity = entityManager.find(MyEntity.class, key, LockModeType.PESSIMISTIC_WRITE);

问题是关于跳过缓存而不是关于锁定。

为什么不直接将请求的锁与查询本身一起传递?

MyEntity entity = entityManager.find(MyEntity.class, key, LockModeType.PESSIMISTIC_WRITE);

据我了解,这正是您想要的。 (documentation)

我刚刚在 EntityManager 中找到了一个方法 getReference,它获取一个实例,其状态可能会延迟获取。如文档中所述:

Get an instance, whose state may be lazily fetched. If the requested instance does not exist in the database, the EntityNotFoundException is thrown when the instance state is first accessed. (The persistence provider runtime is permitted to throw the EntityNotFoundException when getReference is called.) The application should not expect that the instance state will be available upon detachment, unless it was accessed by the application while the entity manager was open.

作为在一次查询中通过 ID 查找和锁定最新实体的可能解决方案,我们可以使用下一个代码:

MyEntity entity = entityManager.getReference(MyEntity.class, key);
entityManager.refresh(entity, LockModeType.PESSIMISTIC_WRITE);

此查询将创建一个实体(无数据库查询),然后刷新并锁定该实体。