尽管禁用共享缓存,为什么需要JPA实体刷新?

时间:2017-06-07 20:19:00

标签: java hibernate jpa eclipselink jpa-2.0

我正在使用Eclipselink for JPA,并且有一个webapp,可以在配置的时间间隔内读取表格。数据库由工具外部修改以发布一些数据。现在我的webapp在一个Entity上创建一个getAll()并将结果作为一个列表获取。但是,每次我获得与第一个查询相同的结果列表。令人惊讶的是,新条目和删除的条目在结果列表中按预期反映出来。如果我更新条目,它仍然会获得原始/旧结果。

从我的搜索中,stackoverflow中的大多数答案都指向JPA级缓存,并且可以归纳为这些

  • 按设置<shared-cache-mode>NONE</shared-cache-mode>
  • 停用共享缓存
  • (可选)使用@Cacheable(false)
  • 选择性地禁用实体上的缓存
  • 执行em.getEntityManagerFactory().getCache().evictAll()
  • 退出缓存
  • 还有一些其他/旧的/ pre-JPA 2.0和特定于供应商的解决方案在persistence.xml中设置了一些属性

但是,这些解决方案都不适用于我的情况。我遇到的最接近的答案是this, which says that

  

会话缓存中已存在的任何ID都与已知实体匹配,而未根据数据库状态填充任何非ID。以前已知的实体根本不会从数据库中刷新。

虽然这是在Hibernate的背景下,但我在Eclipselink中遇到了同样的问题。因此,在列表上引入刷新后,我得到了预期的结果。

T objects = getAll(); 
for (T objects : object) 
    em.refresh(object) 

List<T> getAll() {
  EntityManager em = entityManagerFactory.createEntityManager();
  return  em.createQuery(em.getCriteriaBuilder().createQuery(type)).getResultList();
}

有人可以在Eclipselink的上下文中解释这个Session cache,并解释为什么shared-cache配置对此没有影响吗?事务是否透明地解决了这个问题(读取事务)?是否有优雅的解决方案/ JPA配置,而不是每次都在对象上刷新?

2 个答案:

答案 0 :(得分:2)

从JPA 2.0开始,您可以使用查询提示来绕过或刷新缓存。

Query query = entitymanager.createQuery("select student FROM Student student");
query.setHint("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);

Here是个很好的解释

答案 1 :(得分:1)

您提到的所有内容都指的是共享缓存,但JPA中有两个级别的缓存。共享缓存(第2级)和EntityManager管理实体缓存(第1级)。 EntityManagers用于表示事务工作空间。您应该在适当的时候获取新的Entitymanager实例,而不是使用单个实例,或者在其上调用em.clear()来释放资源。