FetchMode在Spring Data JPA中是如何工作的

2022-08-31 09:41:57

在我的项目中,我确实有三个模型对象(帖子末尾的模型和存储库片段)之间的关系。

当我调用它时,它确实触发了三个选择查询:PlaceRepository.findById

(“sql”)

  1. SELECT * FROM place p where id = arg
  2. SELECT * FROM user u where u.id = place.user.id
  3. SELECT * FROM city c LEFT OUTER JOIN state s on c.woj_id = s.id where c.id = place.city.id

这是相当不寻常的行为(对我来说)。据我所知,在阅读Hibernate文档后,它应该始终使用JOIN查询。在类中更改为 (使用附加 SELECT 的查询)时,查询没有区别,更改为 (使用 JOIN 进行查询)时,类的查询相同。FetchType.LAZYFetchType.EAGERPlaceCityFetchType.LAZYFetchType.EAGER

当我使用灭火时,有两个选择:CityRepository.findById

  1. SELECT * FROM city c where id = arg
  2. SELECT * FROM state s where id = city.state.id

我的目标是在所有情况下都有一个 sam 行为(要么总是 JOIN,要么 SELECT,但 JOIN 是首选)。

模型定义:

地方:

@Entity
@Table(name = "place")
public class Place extends Identified {

    @Fetch(FetchMode.JOIN)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id_user_author")
    private User author;

    @Fetch(FetchMode.JOIN)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "area_city_id")
    private City city;
    //getters and setters
}

城市:

@Entity
@Table(name = "area_city")
public class City extends Identified {

    @Fetch(FetchMode.JOIN)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "area_woj_id")
    private State state;
    //getters and setters
}

存储 库:

PlaceRepository

public interface PlaceRepository extends JpaRepository<Place, Long>, PlaceRepositoryCustom {
    Place findById(int id);
}

用户存储库:

public interface UserRepository extends JpaRepository<User, Long> {
        List<User> findAll();
    User findById(int id);
}

城市存储库:

public interface CityRepository extends JpaRepository<City, Long>, CityRepositoryCustom {    
    City findById(int id);
}

答案 1

我认为Spring Data忽略了FetchMode。在处理 Spring Data 时,我总是使用 和 注释@NamedEntityGraph@EntityGraph

@Entity
@NamedEntityGraph(name = "GroupInfo.detail",
  attributeNodes = @NamedAttributeNode("members"))
public class GroupInfo {

  // default fetch mode is lazy.
  @ManyToMany
  List<GroupMember> members = new ArrayList<GroupMember>();

  …
}

@Repository
public interface GroupRepository extends CrudRepository<GroupInfo, String> {

  @EntityGraph(value = "GroupInfo.detail", type = EntityGraphType.LOAD)
  GroupInfo getByGroupName(String name);

}

在此处查看文档


答案 2

首先,并且是对抗性的,因为等同于JPA。@Fetch(FetchMode.JOIN)@ManyToOne(fetch = FetchType.LAZY)@Fetch(FetchMode.JOIN)FetchType.EAGER

急切提取很少是一个好的选择,对于可预测的行为,最好使用查询时间指令:JOIN FETCH

public interface PlaceRepository extends JpaRepository<Place, Long>, PlaceRepositoryCustom {

    @Query(value = "SELECT p FROM Place p LEFT JOIN FETCH p.author LEFT JOIN FETCH p.city c LEFT JOIN FETCH c.state where p.id = :id")
    Place findById(@Param("id") int id);
}

public interface CityRepository extends JpaRepository<City, Long>, CityRepositoryCustom { 
    @Query(value = "SELECT c FROM City c LEFT JOIN FETCH c.state where c.id = :id")   
    City findById(@Param("id") int id);
}

推荐