为什么加载惰性集合

why the lazy collection is loaded

我有一个项目实体与事件实体具有一对多关系

public class Project {
   ....

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

}

我有一个项目服务class

@Service
@Transactional
public class ProjectService {

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

还有一个项目控制器

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

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

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

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

您的实体仍然附加到:

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

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

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

不代表Project.events没有加载。意思是一调用Project.getEvents()就加载

这发生在 JSON 序列化(当 ProjectController.getAllProject() returns 它的响应时)。

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

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

编辑:如果您使用的是spring-boot,则默认注册OpenEntityManagerInViewInterceptor

Spring web request interceptor that binds a JPA EntityManager to the thread for the entire processing of the request. Intended for the "Open EntityManager in View" pattern, i.e. to allow for lazy loading in web views despite the original transactions already being completed.

您可以通过将此行添加到 application.properties 来禁用此行为:

spring.jpa.open-in-view=false

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

有两种可能:

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

    这在 demo/small 应用程序中通常被认为是可以接受的行为,但在更大更复杂的应用程序中它是非常不受欢迎的,因为您的查询应该 return 您的视图、控制器或逻辑所需的完全初始化的实体.

  2. JSON 库启用了一个休眠插件,它能够在序列化过程中重新连接和水化实体。

否则,您期望的默认行为是 Session/EntityManager 已关闭并且实体一旦被服务 return 分离就会是准确的。否则预期的行为将是 LazyInitializationException