Java Spring JPA优化可传递@manytone抓取
在我的项目中,我有三个这样的实体:Java Spring JPA优化可传递@manytone抓取,java,mysql,spring,hibernate,jpa,Java,Mysql,Spring,Hibernate,Jpa,在我的项目中,我有三个这样的实体: @Entity public class A { @Id private int id; } @Entity public class B { @Id private int id; @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false) @OnDelete(act
@Entity
public class A {
@Id
private int id;
}
@Entity
public class B {
@Id
private int id;
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private A a;
}
@Entity
public class C {
@Id
private int id;
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private B b;
}
正如您所看到的,C
与a
有一个正的多音关系。
现在,我想使用我的JpaRepository
获取所有带有特定a
的C
:
public interface CRepository extends JpaRepository<C, Integer> {
List<C> findAllByBA(A a);
}
公共接口证书扩展了JPA证书{
列出findAllByBA(A);
}
这将导致以下Hibernate sql查询(这很好):
休眠:选择。。。从c c0_uu交叉连接b b1_u,其中c0_u.b_uid=b1_u.id和b1_u.a_uid=
但之后,我得到了针对每个不同B
的另一个查询(可能有几千个,所以不好):
休眠:选择。。。从b0_uu内部连接b0_u上的a1_u.a_uid=a1_u.id,其中b0_u.id=
显然,这可以通过使用所有三个表的单个联接来解决。但是我如何告诉Hibernate使用
JpaRepository
在不失去抽象便利的情况下做到这一点呢?额外的、不需要的查询是由于关联是急切的。要避免加载Bs,应使关联变为惰性:
@ManyToOne(fetch: FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
我通常让每个人都变得懒惰。当您对Bs不感兴趣,或者事先不知道是否需要加载Bs时,使关联延迟可以避免加载Bs。如果您知道希望将Bs与Cs一起加载,则只需在查询中显式加载它们:
@Query("select c from C c left join fetch c.b where c.b.a = ?")
额外的、不需要的查询是由关联是急切的这一事实引起的。要避免加载Bs,应使关联变为惰性:
@ManyToOne(fetch: FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
我通常让每个人都变得懒惰。当您对Bs不感兴趣,或者事先不知道是否需要加载Bs时,使关联延迟可以避免加载Bs。如果您知道希望将Bs与Cs一起加载,则只需在查询中显式加载它们:
@Query("select c from C c left join fetch c.b where c.b.a = ?")
为什么不直接使用@query注释?@gtosto我以前没有使用过
@query
。它如何与@ManyToOne
?为什么不直接使用@query annotation?@gtosto我以前没有使用过@query
。它是如何与@manytone
协同工作的?“我通常会让每个关联都变得懒惰。”不!这是一个非常糟糕的主意,在这里没有任何意义,因为即使关系很紧张,也可以使用join-fetch。如果将所有关联都设置为惰性,那么最终将得到大量初始化代码。另外,LAZY只适用于非可选的ToOne引用。对不起,这不是我的解决方案。我正在使用vaadin UI中的实体,我不想用hibernate会话污染UI。查询(“select c from c join fetch c.b where c.b.a=?”)应该适用于您的情况,而不需要延迟。试试看。否则,问题是您是否真的想要实体,还是最好使用DTO。也许你能多解释一下你想要达到的目标。@SimonMartinelli问题是,我知道我在做什么。因此,我不喜欢加载默认情况下不需要的东西(使事情变得急切正是导致大量无用的查询和初始化的原因),并在需要时使用join-fetch高效地加载事情。不,lazy可以很好地处理可选的toOne关联。@F43nd1r您能澄清一下“我不想用hibernate会话污染UI”是什么意思吗。为什么您认为使用连接获取加载关联并让hibernate使用EAGER加载关联会有什么不同呢?“我通常会让每个关联都变懒。”不!这是一个非常糟糕的主意,在这里没有任何意义,因为即使关系很紧张,也可以使用join-fetch。如果将所有关联都设置为惰性,那么最终将得到大量初始化代码。另外,LAZY只适用于非可选的ToOne引用。对不起,这不是我的解决方案。我正在使用vaadin UI中的实体,我不想用hibernate会话污染UI。查询(“select c from c join fetch c.b where c.b.a=?”)应该适用于您的情况,而不需要延迟。试试看。否则,问题是您是否真的想要实体,还是最好使用DTO。也许你能多解释一下你想要达到的目标。@SimonMartinelli问题是,我知道我在做什么。因此,我不喜欢加载默认情况下不需要的东西(使事情变得急切正是导致大量无用的查询和初始化的原因),并在需要时使用join-fetch高效地加载事情。不,lazy可以很好地处理可选的toOne关联。@F43nd1r您能澄清一下“我不想用hibernate会话污染UI”是什么意思吗。为什么您认为使用join-fetch加载关联和让hibernate使用EAGER加载关联会有什么不同?