OneToMany(fetch = FetchType.EAGER)是否执行N + 1个查询

时间:2018-12-27 01:30:31

标签: database spring hibernate jpa

我正在使用Spring Boot,Spring Data和Hibernate开发应用程序。我有一个实体“ Client”,它与另一个实体“ Reservation”具有“ onetomany”的关系,如下所示:

@Entity
public class Client implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany( mappedBy = "client", fetch=FetchType.EAGER)
    @Fetch(value = FetchMode.JOIN)
    private Set<Reservation> reservations = new HashSet<>();
}

我已经实现了JpaRepository接口,因此可以操纵客户端数据:

public interface ClientRepository extends JpaRepository<Client, Long> {}

在服务类中,我实现了一种在数据库中查找所有客户端的方法:

@Service
public class ClientService {

@Autowired
private ClientRepository clientRepository;

@Transactional(readOnly = true)
public List<Client> findAll() {

    return clientRepository.findAll();
}}

findAll()的执行效果很好,并返回了所有客户端及其保留。但是,在我的sql日志中,尽管我已经在我的客户实体中设置了fetch=FetchType.EAGER,但我已经执行了N + 1个查询(客户数为N)。我以为hibernate将创建一个查询,其中将所有必要的数据连接起来以获取客户及其重新定位信息。

因此,我被迫通过查询显式加入客户端和预订:

    @Query("select client from Client client left join fetch client.reservations")
public List<Client> findAllEager();

我还发现了另一种选择,该选择仅允许执行两个查询来检索所有客户端及其保留:

    @OneToMany(mappedBy = "client", fetch = FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)

我注意到从JPA eager fetch does not join的讨论来看,@OneToMany(fetch=FetchType.EAGER) @Fetch(value = FetchMode.JOIN)只会执行一个查询来检索结果,这与我的情况无关。

OneToMany(fetch=FetchType.EAGER)是否执行N + 1个查询以获取数据?

1 个答案:

答案 0 :(得分:1)

@OneToMany(fetch=FetchType.EAGER)仅定义何时提取相关实体,而不定义如何提取实体。 (即是通过单个联接的SQL还是多个分离的SQL提取),因此它可以执行N + 1个查询。

@Fetch(value = FetchMode.JOIN)定义如何获取相关实体。但是,仅当使用ID直接获取实体时(即通过entityManager.find(Client.class, 100)获取实体,但对JPQL查询或Criteria API无效。)被Hibernate用户指南称为below):

  

之所以不使用JPQL查询来获取多个   部门实体是因为FetchMode.JOIN策略是   被查询获取指令覆盖。

     

要通过JPQL查询获取多个关系,请使用JOIN FETCH   指令必须改为使用。

     

因此,FetchMode.JOIN在获取实体时非常有用   直接通过其标识符或自然ID。

Spring数据在内部使用Criteria API进行findAll()查询,因此@Fetch(value = FetchMode.JOIN)不会有任何效果。您必须显式使用JOIN FETCH查询来避免N + 1个查询。