我使用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;
}
假设我在同一个会话中有多个流程:
A.x
A
实体A
; B
是否包含s2="..."
醇>
对于这些查询中的每一个,我都可以
A.x
和B
撰写获取ida
/ s2
的特定查询
或A
对象,或A.Bset()
然后使用java循环获取B
内所需的Bset()
最有效的方式是什么?
谢谢
答案 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缓存并直接进入数据库。如果您发现自己需要执行错过缓存的查询,则可能需要查看查询缓存。