如何在 Spring Controller 中获取与 JPA 和 Hibernate 的 FetchType.LAZY 关联 [英] How to fetch FetchType.LAZY associations with JPA and Hibernate in a Spring Controller

查看:27
本文介绍了如何在 Spring Controller 中获取与 JPA 和 Hibernate 的 FetchType.LAZY 关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Person 类:

I have a Person class:

@Entity
public class Person {

    @Id
    @GeneratedValue
    private Long id;

    @ManyToMany(fetch = FetchType.LAZY)
    private List<Role> roles;
    // etc
}

具有惰性的多对多关系.

With a many-to-many relation that is lazy.

在我的控制器中我有

@Controller
@RequestMapping("/person")
public class PersonController {
    @Autowired
    PersonRepository personRepository;

    @RequestMapping("/get")
    public @ResponseBody Person getPerson() {
        Person person = personRepository.findOne(1L);
        return person;
    }
}

而PersonRepository就是这段代码,根据本指南

And the PersonRepository is just this code, written according to this guide

public interface PersonRepository extends JpaRepository<Person, Long> {
}

然而,在这个控制器中我实际上需要惰性数据.如何触发加载?

尝试访问它会失败

未能延迟初始化角色集合:no.dusken.momus.model.Person.roles,无法初始化代理 - 否会话

failed to lazily initialize a collection of role: no.dusken.momus.model.Person.roles, could not initialize proxy - no Session

或其他例外情况,具体取决于我的尝试.

or other exceptions depending on what I try.

我的xml-description,以备不时之需.

谢谢.

推荐答案

你必须显式调用惰性集合来初始化它(通常的做法是调用 .size() 为此目的).在 Hibernate 中有一个专门的方法(Hibernate.initialize()),但 JPA 没有对应的方法.当然,当会话仍然可用时,您必须确保调用已完成,因此使用 @Transactional 注释您的控制器方法.另一种方法是在控制器和存储库之间创建一个中间服务层,它可以公开初始化惰性集合的方法.

You will have to make an explicit call on the lazy collection in order to initialize it (common practice is to call .size() for this purpose). In Hibernate there is a dedicated method for this (Hibernate.initialize()), but JPA has no equivalent of that. Of course you will have to make sure that the invocation is done, when the session is still available, so annotate your controller method with @Transactional. An alternative is to create an intermediate Service layer between the Controller and the Repository that could expose methods which initialize lazy collections.

请注意,上述解决方案很简单,但会导致对数据库的两个不同查询(一个针对用户,另一个针对其角色).如果您想获得更好的性能,请将以下方法添加到您的 Spring Data JPA 存储库接口:

Please note that the above solution is easy, but results in two distinct queries to the database (one for the user, another one for its roles). If you want to achieve better performace add the following method to your Spring Data JPA repository interface:

public interface PersonRepository extends JpaRepository<Person, Long> {

    @Query("SELECT p FROM Person p JOIN FETCH p.roles WHERE p.id = (:id)")
    public Person findByIdAndFetchRolesEagerly(@Param("id") Long id);

}

此方法将使用 JPQL 的 fetch join 子句急切地加载角色关联到数据库的单次往返,因此将减轻上述解决方案中两个不同查询所导致的性能损失.

This method will use JPQL's fetch join clause to eagerly load the roles association in a single round-trip to the database, and will therefore mitigate the performance penalty incurred by the two distinct queries in the above solution.

这篇关于如何在 Spring Controller 中获取与 JPA 和 Hibernate 的 FetchType.LAZY 关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆