由于隐私问题,我没有发布代码,但是几乎我在一对一关系中有2个实体(可以是多对一关系,但在这种情况下,我认为它并不重要),如下所示:< / p>
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
//...
}
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String subject;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private User otherUser;
//...
}
The repository looks like this
@EntityGraph(attributePaths = {"otherUser"})
Iterable<Post> findAll(Predicate predicate);
因此,我重写了它们默认提供的findAll方法,因为我仍然想使用谓词,并且我仍然想将查询联接到另一个表。这几乎完美地工作。创建的查询如下所示:
select
post0_.id as id1_4_0_,
user0_.id as id1_0_1_,
post0_.subject as subject2_4_0_,
user0_.name as name2_0_1_,
user0_.email as email3_0_1_
from
Post post0_
left outer join User user0_ on post0_.id = user0_.id
where
***contents of Predicate****
现在的问题是,如果用户从该查询中返回的基本为空(该用户的所有属性均为空,则意味着不存在符合条件的条件),则Spring将直接向用户表中创建其他选择查询以查找用户。例如,假设有一个ID为4的帖子。如果没有id = 4的用户,那么Spring将创建并运行一个普通查询,如下所示:
select
user0_.id as id1_0_1_,
user0_.name as name2_0_1_,
user0_.email as email3_0_1_
from
User user0_
left outer join User user0_ on post0_.id = user0_.id
where
user0_id = 4
如果数据集很大并且包含不符合原始联接查询的大量记录,则将创建并执行太多其他查询,这是一个问题。如果不符合联接条件,那么我希望该实体记录被忽略。使用该示例,我希望忽略ID与帖子ID不匹配的任何用户,而不是其他select语句。有没有办法阻止那些额外的选择查询的创建?
答案 0 :(得分:1)
假设您通过日志语句使用 Hibernate,我相信您遇到了 n+1 sql 加载情况,需要添加不同/额外的 FETCH 指令以使 otherUser
关联急切地获取,因此它不会t 需要后续的 select 语句。
我能找到的有关该主题的最权威文档在这里:https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#fetching
我建议您先将 FetchType.LAZY
更改为 FetchType.EAGER
。如果将 JPA 注释 FetchType.EAGER
放在 otherUser
成员变量上不能解决您的问题,请考虑使用 @Fetch(FetchMode.JOIN)
进一步加强它。
此外,为了完整起见,如果您选择使用基于查询的方法来检索(即 JPQL),那么您可以在 JPQL 中包含 FETCH 指令以根据需要实现效果。