为什么加载惰性集合

时间:2016-03-10 10:59:51

标签: java spring hibernate hibernate-entitymanager

我有一个与事件实体

具有oneToMany关系的Project实体
public class Project {
   ....

   @OneToMany(mappedBy = "dossier", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
   private List<Event> events;

}

我有一个ProjectService类

@Service
@Transactional
public class ProjectService {

    public List<Project> findAll() {
        return (List<Project>) projectRepository.findAll();
    }
}

和ProjectController

@RestController
@RequestMapping(value = "/projects")
public class ProjectController {

    @RequestMapping(method= RequestMethod.GET)
    public List<Project> getAllProject() {
        return projectService.findAll();
    }
}

在我的客户端代码中,我看到项目的事件已加载,我不明白为什么。

我预计在DossierService中方法findAll的事务结束时,实体将被分离。显然,我的实体仍然附着,因为在我的控制器中的jackson序列化期间检索了事件。

3 个答案:

答案 0 :(得分:7)

Project.events默认为延迟加载,因为它是OneToMany关系。

这并不意味着未加载Project.events。这意味着只要调用Project.getEvents()就会加载它。

这发生在JSON序列化中(当ProjectController.getAllProject()返回其响应时)。

为了防止这种情况,有两种方法:

  • 您可以在project.setEvents(null)返回的每个项目上显式调用ProjectService(或空列表)。
  • 或者您在@JsonIgnore上添加Project.events注释。

编辑:如果您使用的是spring-boot,默认情况下会注册OpenEntityManagerInViewInterceptor

  

Spring Web请求拦截器,它将JPA EntityManager绑定到线程以进行整个请求处理。用于“Open EntityManager in View”模式,即允许在Web视图中进行延迟加载,尽管原始事务已经完成。

您可以通过将此行添加到application.properties

来禁用此行为
spring.jpa.open-in-view=false

使用此配置,在休眠会话之外调用getter将导致LazyInitializationException

答案 1 :(得分:1)

有两种可能性:

  1. 已定义OpenSessionInViewOpenEntityManagerInView bean。这种类型的bean分别导致SessionEntityManager在调用控制器时打开,并保持打开状态,直到控制器的主体被序列化为止。

    它通常被认为是演示/小型应用程序中可接受的行为,但它在大型更复杂的应用程序中非常不受欢迎,因为您的查询应返回视图,控制器或逻辑所需的完全初始化实体。

  2. JSON库启用了一个hibernate插件,它能够在序列化过程中重新附加和保护实体。

  3. 否则,一旦服务返回,Session / EntityManager关闭并且实体分离后,您期望的默认行为是准确的。否则预期的行为将是LazyInitializationException

答案 2 :(得分:0)

您的实体仍然附加,直到:

  • 您要求实体管理器使用entityManager.clear()
  • 清除持久性上下文
  • 您要求实体经理使用entityManager.detach(项目)为每个项目分离您的实体。

但是如果您知道您的事件将在大多数时间加载,那么您应该考虑使用FetchType.EAGER以便一次性获取所有内容。