代码之家  ›  专栏  ›  技术社区  ›  Suraj Gautam

本例中spring事务是如何工作的,以及如何解决LazyInitializationException?

  •  0
  • Suraj Gautam  · 技术社区  · 6 年前

    我正在 组织。冬眠LazyInitializationException 例外据我所知,之所以会出现此问题,是因为我在用户实体中懒散地获取了概要文件对象,并且在初始化代理对象之前,会话已关闭。

    执行findAll()方法后会话是否关闭?是否有其他选项可以在同一事务中执行findAll()方法并进行解析,而不是在findAll()方法中进行解析?

    我只想知道当调用服务中的findAll方法和UserUtils类的稍后解析方法时,spring事务是如何工作的?

    我还发现在@Transactional annotation中使用传播将有所帮助。会吗?请让我说清楚。

    现在让我们看看一些代码。

    使用者JAVA

    package com.technep.test.entity;
    
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.OneToOne;
    import javax.persistence.Table;
    import lombok.Getter;
    import lombok.Setter;
    
    @Entity
    @Getter
    @Setter
    @Table(name="user")
    public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    private String name;
    
    private String fatherName;
    
    private String motherName;
    
    @OneToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="user_profile_id")
    private Profile profile;
    }
    

    轮廓JAVA

    @Entity
    @Table(name="profile")
    @Getter
    @Setter
    public class Profile {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    @Column(name="profile_name")
    private String name;
    
    @Column(name="created_date")
    private Date createdDate;
    
    @Column(name="last_modified_date")
    private Date lastmodifiedDate;
    
    }
    

    用户控制器。JAVA

    @RestController
    public class UserController {
    
    @Autowired
    private UserService userService;
    
    
    @GetMapping(value = "/api/users")
    public ResponseEntity<List<UserResponseDTO>> getListOfUsers(){
        List<User> users = userService.findAll();
        List<UserResponseDTO> responseDTOs =UserUtils.parseUserToDTO(users);
        return new ResponseEntity<List<UserResponseDTO>>(responseDTOs,HttpStatus.OK);
    }
    }
    

    用户服务。JAVA

    public interface UserService {
    
    User findById(Integer id);
    
    List<User> findAll();
    
    }
    

    用户存储库。JAVA

    public interface UserRepository extends JpaRepository<User, Integer>{
    
    }
    

    UserServiceImpl。JAVA

    @Service
    @Transactional
    public class UserServiceImpl implements UserService{
    
    
    @PersistenceContext
    private EntityManager entityManager;
    
    @Autowired
    private UserRepository repository;
    
    @Override
    public User findById(Integer id) {
        return repository.findOne(id);
    }
    
    @Override
    public List<User> findAll() {
       return repository.findAll();
    }
    
    }
    

    UserUtils。JAVA

    public class UserUtils {
    
    public static List<UserResponseDTO> parseUserToDTO(List<User> users) {
    
        List<UserResponseDTO> responseDTOs  = new ArrayList<>();
    
        users.forEach(user -> {
            UserResponseDTO responseDTO = new UserResponseDTO();
            responseDTO.setId(user.getId());
            responseDTO.setName(user.getName());
            responseDTO.setProfileName(user.getProfile().getName());
            responseDTO.setProfileCreatedDate(user.getProfile().getCreatedDate());
            responseDTOs.add(responseDTO);
        });
    
        return responseDTOs;
    }
    
    }
    

    例外情况是:

    org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:147)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:260)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:68)
    at com.technep.test.entity.Profile_$$_jvst12b_0.getName(Profile_$$_jvst12b_0.java)
    at com.technep.test.utils.UserUtils.lambda$parseUserToDTO$0(UserUtils.java:27)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at com.technep.test.utils.UserUtils.parseUserToDTO(UserUtils.java:23)
    at com.technep.test.controller.UserController.getListOfUsers(UserController.java:24)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    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:52)
    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:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
    
    4 回复  |  直到 6 年前
        1
  •  1
  •   JustinKSU    6 年前

    执行findAll()方法后会话是否关闭?

    对默认情况下,存储库上的任何操作都是原子操作。

    是否有其他选项可以执行findAll()方法并在 是否在findAll()方法中分析相同的事务?

    对如果您有@Transactional围绕该方法执行这两个操作。在该方法返回之前,事务将保持打开状态。

    我只想知道当findAll方法 调用UserUtils类的from service and later parse方法?

    您有多种选择。

    1. 添加 @Transactional 控制器上的注释getListOfUsers应该可以工作。

    2. 但是,您可以考虑使用一种既搜索所有用户又创建响应的服务方法。你会想把 @事务性 改为使用此方法。

    3. 第三种选择是创建一个命名查询,该查询显式请求作为查询的一部分急切地获取概要文件。

    我想说第二个或第三个选项比第一个更好。

        2
  •  1
  •   locus2k    6 年前

    我很好奇你为什么在偷懒的时候有一个OneToOne?典型的OneToOnes不是这样设置的。延迟加载是一种设计模式,用于尽可能延迟对象的初始化,通常在获取列表时使用。使用Hibernate,当用户尝试获取资源时,事务通常会关闭。我建议删除懒散的Fetch并尝试这样做。

    如果你不能,这里有一些其他有用的建议,你可以试试。

    实际上,您可以在 UserRepository 要获取您的配置文件,请执行以下操作:

    @Query("SELECT user FROM User user JOIN FETCH user.profile")
    List<User> findAll();
    

    这将覆盖内置的findAll,并使用已经为您获取的用户配置文件获取列表。

    您可以做的另一件事是创建一个UserProfileRepository,并在获得用户后获取配置文件,例如:

    public interface UserProfileRepository extends JpaRepository<UserProfile, Integer>{
      Profile findById(Integer id);
    }
    

    然后在DTO中,您可以执行以下操作:

    users.forEach(user -> {
        UserResponseDTO responseDTO = new UserResponseDTO();
        responseDTO.setId(user.getId());
        responseDTO.setName(user.getName());
    
        Profile profile = profileRepository.findById(user.getProfileId());        
    
        responseDTO.setProfileName(profile.getName());
        responseDTO.setProfileCreatedDate(profile.getCreatedDate());
        responseDTOs.add(responseDTO);
    });
    
        3
  •  1
  •   Robert Niestroj    6 年前

    解决此问题的最佳方法是获取 List<UserResponseDTO> 直接从数据库中获取实体,而无需先获取实体,然后进行转换。

    在存储库中创建方法:

    @Query("select new com.company.UserResponseDTO(u.id, u.name, u.profile.name, u.profile.createdDate) from User u")
    List<UserResponseDTO> findAllAsDTO();
    

    确保您的UserResponseDTO有一个适当的构造函数,该构造函数按此顺序接受此参数。

    这是最有效的方法。它通过不提取实体来节省内存,这些实体需要额外的内存进行脏检查。此外,这是更具可扩展性的,因为如果有人向用户或概要文件实体添加属性,他们不会影响此查询。最后,这也是更少的代码编写。

    我推荐这种方法。

    这种技术被称为 JPQL Constructor Expression

        4
  •  0
  •   Piotr Podraza    6 年前

    您正在尝试延迟加载 profile 交易之外-因此例外。

    要解决此问题,可以将实体映射到DTO内部 UserService 实施对你来说,这似乎是最合适的解决方案。

    您还可以获取 轮廓 急切地或将控制器方法标记为 @Trasnational 但这似乎不是一个好主意,因为控制器不包含任何业务逻辑。