org.hibernate.LazyInitializationException:未能延迟初始化角色集合:在 Spring boot 中

问题描述 投票:0回答:1

在我们的例子中,有两个实体 User 和 UserRole 这两个实体之间的关系是一对多关系 在我们的例子中,我们执行一些操作,例如使用 hibernate 获取用户数据,然后我们从用户实体中延迟获取 UserRole

public class User {

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<UserRole> userRoles;
}

public class UserRole {

    @ManyToOne
    User user;

    String name;
}

public String getUserRoleName(Long userId) {

    User user = repository.findById(userId);

    List<UserRole> userRoles = user.getUserRoles();
       
    String name = userRoles.stream().map(obj -> obj.getName()).collect(Collectors.joining(", "));

    return name;
}

在上面的代码中,我们得到以下异常

运行时错误消息是:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
co.entity.User.userRoles, could not initialize proxy - no Session   at
org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606) at
org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218) at
org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585) at
org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) at
org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:387) at
java.base/java.util.Spliterators$IteratorSpliterator.estimateSize(Spliterators.java:1821) at
java.base/java.util.Spliterator.getExactSizeIfKnown(Spliterator.java:408) at
java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:483) at
java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at
java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) at
java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at
java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) at co.service.UserService.getUserRoleName(UserService.java:20)     at
co.controller.UserController.getUserRoleName(UserController.java:10) at jdk.internal.reflect.GeneratedMethodAccessor193.invoke(Unknown
Source) at
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566)  at
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) at
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) at
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) at
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878) at
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792) at
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) at
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) at
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)  at
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)     at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at
org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at
org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at
org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93) at
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) at
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) at
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888) at
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597) at
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:829)

我们使用@Transactional注解来解决这个问题

java spring-boot hibernate one-to-many lazy-initialization
1个回答
0
投票

堆栈跟踪告诉您需要了解的所有信息:

You are trying to access the roles after the session is closed, and as a result, the code throws a LazyInitializationException.

您有多种选择来修复它:

将获取类型声明为 Eager

  @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
  private List<UserRole> userRoles;

但在我看来,EAGER 获取类型不是一个好主意,因为它告诉 JPA 始终获取数据,即使这些数据不是必需的。

第二个解决方案是在 JPQL 中使用 JOIN FETCH 指令

在存储库中声明一个自定义查询,然后您可以获取它

而不是写作

User user = repository.findById(userId); // default method from repository

执行此操作(在存储库中创建自定义方法,如下所示): 存储库

@Query("SELECT u FROM User u JOIN FETCH u.roles WHERE u.userId = :userId")
List<User> findUserAndUserRolesByUserId(@Param("userId") Long userId)

然后在你的方法中替换:

User user = repository.findById(userId);

致:

User user = repository.findUserAndUserRolesByUserId(userId);

您可以找到更多修复它的方法这里在 stackoverflow 上也有很多关于这个主题的问答,因为它是使用 hibernate 作为 ORM 时最流行的问题之一。

© www.soinside.com 2019 - 2024. All rights reserved.