有效查询使用hibernate缓存

时间:2011-11-16 07:36:00

标签: hibernate caching jpa-2.0

我使用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. 获取A.x
  2. 获取整个A实体
  3. 使用A;
  4. 检查B是否包含s2="..."

    对于这些查询中的每一个,我都可以

    • 根据A.xB撰写获取ida / s2的特定查询 或
    • 假设Hibernate保存缓存并始终获取A对象,或A.Bset()然后使用java循环获取B内所需的Bset()

    最有效的方式是什么?

    谢谢

2 个答案:

答案 0 :(得分:1)

对于用例1和2,我只需加载整个实体。二级缓存同样可以正常工作。除非您的A对象非常大(很多属性),否则您将看不到与之相比有任何差异:

SELECT a.x FROM A a WHERE a.id = :id

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

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

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

如果查询返回某些内容,则表示a包含b,且s2。这应该比懒惰加载Bset并迭代它快得多。考虑启用查询缓存。

但是,如果Bset通常较小并且您使用急切提取,则使用Java进行简单过滤可能会更好。这真的取决于你的架构。

答案 1 :(得分:1)

只是警告我不认为A和B之间的上述映射是有效的。当您在关系的OneToMany侧使用mappedBy时,您还需要在B中映射反向关系。

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

不建议使用OneToMany单向关系。

在回答您的问题时,有效使用会话缓存的关键是尽可能使用get()。因此,如果您可以通过@Id获取A,则可以遍历B的映射集合以查找您感兴趣的实例。

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

每当您使用HQL并强制Hibernate执行查询时,您将绕过Session缓存并直接进入数据库。如果您发现自己需要执行错过缓存的查询,则可能需要查看查询缓存。