当前位置: 首页 > 知识库问答 >
问题:

在SpringDataJPA中FetchMode是如何工作的

葛胜泫
2023-03-14

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

当我调用PlaceRepository.findById时,它会触发三个select查询:

(“sql”)

  1. 从id=arg的p处选择*
  2. 从用户u中选择*,其中u.id=place.user.id
  3. 在c.woj_id=s.id,其中c.id=place.city.id上从城市c左外部连接状态s中选择*

(对我来说)那是相当不寻常的行为。在阅读Hibernate文档后,我认为它应该始终使用连接查询。当Place类中的FetchType.LAZY更改为FetchType.EAGER时,查询没有区别(使用附加选择进行查询),当FetchType.LAZY更改为FetchType.EAGER时,城市类的查询也一样(使用JOIN进行查询)。

当我使用CityRepository.findById抑制火灾时,有两种选择:

  1. 从城市c中选择*,其中id=arg
  2. 从州s中选择*,其中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
}

存储库:

存储库

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);
}

共有3个答案

龙兴学
2023-03-14

Spring-jpa使用实体管理器创建查询,如果查询是由实体管理器构建的,Hibernate将忽略读取模式。

以下是我使用的解决方法:

>

重写方法getQuery(规范

@Override
protected TypedQuery<T> getQuery(Specification<T> spec, Sort sort) { 
    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery<T> query = builder.createQuery(getDomainClass());

    Root<T> root = applySpecificationToCriteria(spec, query);
    query.select(root);

    applyFetchMode(root);

    if (sort != null) {
        query.orderBy(toOrders(sort, root, builder));
    }

    return applyRepositoryMethodMetadata(entityManager.createQuery(query));
}

在方法的中间,添加<代码> Apple YoFixMoad(root);应用获取模式,使Hibernate使用正确的联接创建查询。

(不幸的是,我们需要从基类复制整个方法和相关的私有方法,因为没有其他扩展点。)

实施applyFetchMode

private void applyFetchMode(Root<T> root) {
    for (Field field : getDomainClass().getDeclaredFields()) {

        Fetch fetch = field.getAnnotation(Fetch.class);

        if (fetch != null && fetch.value() == FetchMode.JOIN) {
            root.fetch(field.getName(), JoinType.LEFT);
        }
    }
}

劳鹏云
2023-03-14

首先,@Fetch(FetchMode.JOIN)@manytone(Fetch=FetchType.LAZY)是对立的,因为@Fetch(FetchMode.JOIN)相当于JPAFetchType.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);
}
江丰羽
2023-03-14

我认为Spring数据忽略了FetchMode。在处理Spring数据时,我总是使用@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);

}

请检查此处的文档

 类似资料:
  • 问题内容: 我确实在项目中的三个模型对象之间有关系(文章末尾的模型和存储库片段)。 当我调用它时,会触发三个选择查询: (“ sql”) (对我而言)这是非常不正常的行为。据阅读Hibernate文档后所知,它应该始终使用JOIN查询。在类中更改为 查询时(带有附加SELECT 的查询)没有任何区别,而在类更改为 (使用JOIN查询时)则没有变化。 当我使用抑制射击时,有两个选择: 我的目标是在所

  • 在Spark中是如何工作的? 如果我们注册一个对象作为一个表,会将所有数据保存在内存中吗?

  • 我从网上和论坛上看到了关于BatchSize的相关主题,但我仍然不明白一些部分。所以让我们描述一下我理解的和不理解的。 批量取数:选择取数的优化策略。Hibernate通过指定主键或外键列表,在一次选择中检索一批实体实例或集合。 让我们有JPA 2.0,带有Hibernate实现。这些实体: } 因此,我懒得去了解产品中的制造商。因此,当我执行select fetching时,就完成了。所以我有很

  • 我经常把文本输出到文件中。我想知道:是如何工作的? 当我调用时,它是否在文件上写入文本?如果它不写文本,我需要使用flush函数来写数据吗? 例如: 如果while循环中发生错误,文件将在不写入数据的情况下关闭。如果我在while循环中使用函数,那么为什么要使用?如果我错了,请纠正我。

  • 我正从最基本的方面着手研究递归,因为我在过去很挣扎。我在看这个阶乘解: 因此函数会一直调用自己,直到<code>n==0</code>为止。然后在每次调用时返回值。这就是我不明白的:当它从基本条件返回时,它返回一个值,并不断添加每个调用的值。 这些值存储在哪里,以便最终能够返回总和?