【问题标题】:JPA - EntityGraph and Hibernate L2 Cache (ehcache)JPA - EntityGraph 和 Hibernate L2 缓存 (ehcache)
【发布时间】:2017-01-10 06:42:00
【问题描述】:

我有如下定义的一对多关系

@Cacheable
@Entity
@NamedEntityGraph(
    name = "Parent.Child",
    attributeNodes = {
        @NamedAttributeNode("children"),
    }
)
public class Parent {
    private Set<Child> children;
    // getter - setter
}

现在在我的 DAL 中,我正在调用这个方法

@Override
    public Parent getParentWithChildren(int id) {
        EntityGraph<?> graph = entityManager.getEntityGraph("Parent.Child");
        Map<String, Object> props = new HashMap<>();
        props.put("javax.persistence.fetchgraph", graph);
        return entityManager.find(Parent.class, id, props);
    }

由于我已经为 Parent 加载了 Children,我应该能够在事务之外使用 children 集合。但我得到延迟初始化异常。仅当启用休眠 2 级缓存 - ehcache 时才会发生这种情况。如果我从配置中禁用它,它会按预期工作。此外,如果我在 find 之后显式初始化集合,它会按预期工作。那么它是一个错误吗?我正在使用 Hibernate 5.2.6.Final 和 JPA 2.1。

编辑:我注意到的另一件事是实体第一次加载正常,因此该问题必须与休眠和缓存提供程序有关。

【问题讨论】:

  • 我也遇到过类似的情况。我不使用二级缓存。我意识到,如果实体已经在持久性上下文中,则带有 fetchgraph 提示的下一个 em.find 不会从数据库中加载任何内容。在我看来,这也是错误。
  • 我认为会话缓存也会发生同样的情况。这是一个已确认的错误,并标记为在 5.2.10 中解决

标签: spring hibernate jpa ehcache


【解决方案1】:

没有。这不是一个错误。我猜 Hibernate 正在延迟从缓存中加载,直到真正需要为止。除非您要求急切获取,否则实现可以决定是懒惰的。

所以一般规则是在退出事务之前加载您需要的所有内容(准确地说是在关闭 Hibernate 会话之前)。

【讨论】:

  • 我已经在使用 fetch graph 来热切地加载儿童集合
  • 您没有提供足够的信息让我证明这一点,但我怀疑实际上是集合中的对象被代理延迟加载。
  • 查看道具对象。我指定获取图
【解决方案2】:

为了让 Hibernate 使用实体图,必须通过使用值为 CacheRetrieveMode.BYPASSjavax.persistence.cache.retrieveMode 提示绕过二级缓存(例如 EhCache):

final EntityGraph<?> graph = em.getEntityGraph("myGraph");
final Map<String, Object> hints = new HashMap<>();
hints.put("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
hints.put("javax.persistence.fetchgraph", graph);
final SomeEntity entity = em.find(SomeEntity.class, 42, hints);

请注意,二级缓存仍将照常填充。

【讨论】: