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

查看:217
本文介绍了如何在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> {
}

但是,在此控制器中,我实际上需要惰性数据.如何触发其加载?

However, in this controller I actually need the lazy-data. How can I trigger its loading?

尝试访问它会失败,并显示

Trying to access it will fail with

无法延迟初始化角色集合: 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描述.

谢谢.

推荐答案

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

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的获取联接子句来快速加载角色关联到数据库的一次往返中,因此将减轻上述解决方案中两个不同查询所引起的性能损失.

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天全站免登陆