使用实体图时,Spring Data JPA运行其他选择查询

时间:2019-03-15 17:22:58

标签: spring-boot jpa spring-data-jpa entity entitygraph

由于隐私问题,我没有发布代码,但是几乎我在一对一关系中有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语句。有没有办法阻止那些额外的选择查询的创建?

1 个答案:

答案 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 指令以根据需要实现效果。