为什么加载惰性集合

Oli*_*ssé 3 java spring hibernate hibernate-entitymanager

我有一个与Event实体具有oneToMany关系的Project实体

public class Project {
   ....

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

}
Run Code Online (Sandbox Code Playgroud)

我有一个ProjectService类

@Service
@Transactional
public class ProjectService {

    public List<Project> findAll() {
        return (List<Project>) projectRepository.findAll();
    }
}
Run Code Online (Sandbox Code Playgroud)

还有一个ProjectController

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

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

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

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

Arn*_*lle 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
Run Code Online (Sandbox Code Playgroud)

使用此配置,在hibernate会话之外调用getter将导致a LazyInitializationException.

  • @ArnaudDenoyelle 我不明白为什么在序列化期间我的控制器中没有收到 LazyInitializationException 。我期望持久性上下文在我的控制器中关闭,显然在调用方法 findAll 后它仍然打开,因为事件集合被正确检索。spring什么时候打开和关闭持久化上下文?(我以为是每次交易开始和关闭时) (2认同)