JPA JPQL 是从数据库还是从持久化上下文中选择查询读取?

Bau*_*han 4 java mysql hibernate jpa

我有 id=1 的文档实体和一些托管文档对象。

 Document managedDoc = entityManager.find(Document .class, 1);
 managedDoc.setName("changedName");
Run Code Online (Sandbox Code Playgroud)

据我所知,在调用 setter 后,托管文档状态在持久上下文(进一步的 PC)中发生了变化,但数据库中没有任何变化。在我的代码中的某处,我执行以下操作:

 Query query = entityManager.createQuery("from Document");
 List<Document> list = query.getResultList();
 return list;
Run Code Online (Sandbox Code Playgroud)

当我执行如上所示的全选查询时,id=1 的文档是从 DB 还是从 PC 中获取的?从 DB 意味着 select 不会看到新名称,因为新名称仍在 PC 中。

实际上,我的问题是通过更新merge() and flush()并进一步检索所有对象 - 目前我的全选查询没有看到某些字段的新值。看起来合并+刷新是可以的,但 JPA 查询不是从 DB 而是从 PC 读取。但即使我是对的,PC 和 DB 都包含名称的新值,为什么我的全选没有看到它?

此外,全选有时会返回正确/更新的值,有时不会

更新

澄清:

  1. 我通过 entityManager.find(Document .class, 1);
  2. 我创建了一些设置了名称属性的新分离实例。从托管实例获取的 ID 和其他道具。例如, managedDoc = getFromSomeDataStructure(); Document nonManaged = new Document(managedDoc.getId()); nonManaged.setName("newName");
  3. 我通过更新数据库 em.merge(nonManaged);flush();
  4. 在 Workbench 中检查时,我在 DB 中看到了我的更改。
  5. 我按下 F5(甚至 CTRL+F5)按钮,它执行全选 JPQL 查询,在每个奇数按钮上按下==全选查询,我看到非实际的旧值,在每个偶数按钮上按下==全选查询我看到正确的值。

And*_*i I 5

它将从 Persistent Context 中取出,只要它拥有它们。更准确地说:只要您有一个处于托管状态(即在持久性上下文中)的实体,它就不会被覆盖。当然,在使用相同 EntityManager 实例的上下文中。

如果您想从数据库重新获取值,您有不同的可能性:

  1. 在不同的事务中使用另一个 EntityManager(重要!)。
  2. 使用EntityManager.detach()或者如果要清除整个持久性上下文,请使用EntityManager.clear()
  3. EntityManager.refresh()扔出去的实体实例所做的所有更改。


小智 0

正如这里所回答的,我应该为结果列表中的每个项目调用refresh()。但仅仅提神醒脑对我来说不起作用。通过写入在 persistence.xml 中设置 READ COMMITED 后

<property name="hibernate.connection.isolation" value="2" /> 一切都很顺利。

PS 不要忘记将 select 方法标记为 @Transactional,因为如果没有此注释,refresh() 将无法工作。