使用hibernate缓存的高效查询



我使用JPA与Hibernate实现。我的问题可能是有经验的hibernate用户的基本问题:基于hibernate一级缓存编写查询的最有效方法是什么?

例如,我有实体A和实体B:

@Entity
class A{
      private int ida;
      private int x;
      private String s;
    @OneToMany(mappedBy = "ida", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
      private Set<B> Bset;
    }
@Entity
class B{
      private int ida;
      private String s2;
    }

假设我有几个流可能发生在同一个会话中:

  1. get A.x
  2. 获取整个A实体
  3. 检查A是否包含Bs2="...";

对于这些查询,我可以

  • 编写一个特定的查询,通过idas2获取A.x/B
  • 假设Hibernate保存缓存并且总是获取A对象,或者A.Bset(),然后java循环在Bset()中获取所需的B

最有效的方法是什么?

谢谢

对于用例1和2,我只加载整个实体。第二级缓存也同样有效。除非你的A对象非常大(有很多属性),否则与

相比,你不会看到任何区别:
SELECT a.x FROM A a WHERE a.id = :id

更糟糕的是,使用上面的查询不会利用二级缓存。

第三个用例更有趣。这在很大程度上取决于您的需求,但合理的平衡是使用这样的查询:

SELECT B b
WHERE b.s2 == :s2
  AND b.a = :a

如果查询返回一些东西,这意味着a包含b与给定的s2。这应该比惰性加载Bset并迭代它要快得多。考虑启用查询缓存。

但是,如果Bset通常很小,并且您使用即时抓取,那么在Java中进行简单的过滤可能会更好。这取决于你的架构。

只是一个警告,我不认为上面的a和B之间的映射将工作。当您在关系的OneToMany端使用mapappedby时,您还需要映射b中的反向关系

@Entity
class B{
      @ManyToOne
      @JoinColumn(name="aid")
      private A a;
      private String s2;
    }

不建议使用OneToMany的单向关系。

回答你的问题,有效使用会话缓存的关键是尽可能使用get()。因此,如果你可以通过A的@Id得到A,你就可以遍历B的映射集合来找到你感兴趣的实例。

使用get将确保如果A的实例在缓存中,它将被返回(非常快),如果它不在缓存中,它将被添加到缓存中,然后返回给你。然后,下次您通过@Id请求它时,它将从缓存返回。

当你使用HQL并强制Hibernate执行查询时,你将绕过Session缓存而直接进入数据库。如果你发现自己需要执行没有缓存的查询,那么查询缓存可能是值得研究的。

最新更新