关于Spring Data JPA软删除和关联查询N+1的问题

@Entity
@Getter
@Setter
@ToString
@Table(name = "order")
public class Order {
    @Id
    private Long id;
    @Column(name = "account_id")
    private Long accountId;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "account_id", insertable = false, updatable = false)
    private Account account;
}
@Entity
@Getter
@Setter
@ToString
@Table(name = "account")
@SQLDelete(sql = "update account set is_deleted=1 where id=?")
@Where(clause = "is_deleted=0")
public class Account {
    @Id
    private Long id;
    private String account;
    
    @Column(name = "is_deleted")
    private Boolean deleted;
}

如上2个实体类

问题1:查询Order的时候,最后生成的SQL语句不是JOIN连表查询,而是分两步,先查order再通过account_id去account表里查,这样会产生N+1的问题,不是只有懒查询才会这样吗?

问题2:Account使用了软删除,通过@Where(clause = "is_deleted=0")注解,每次查询的时候都会带上这个条件。那么如何可以设置例外呢,比如查询Order并关联查Account这种情况,如果带上这个条件,会出现EntityNotFoundException异常,原因是account里有记录被软删除了。

阅读 5k
1 个回答

问题1已经招到解决办法了,放上来分享下
通过@NamedEntityGraph和@EntityGraph两个注解来实现

在Order类上增加注解

@NamedEntityGraph(name = "Order.account", attributeNodes = {
        @NamedAttributeNode("account")
})
public class Order {
    @Id
    private Long id;
    @Column(name = "account_id")
    private Long accountId;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "account_id", insertable = false, updatable = false)
    private Account account;
}

然后在对应Repository的查询方法上增加注解@EntityGraph
例如:

public interface OrderRepository extends JpaRepository<Order, Long> {
    @EntityGraph(value = "Order.account")
    List<Order> findAll();
}

这样最后生成的查询语句使用的就是LEFT JOIN了,解决了N+1的问题

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题