当前位置: 首页 > 知识库问答 >
问题:

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

张浩阔
2023-03-14

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

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

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

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

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

User.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)

共有3个答案

臧友樵
2023-03-14

解决此问题的最佳方法是获取一个列表

在存储库中创建方法:

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

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

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

我推荐这种方法。

这种技术称为JPQL构造函数表达式。

秦新立
2023-03-14

我很好奇为什么你在延迟获取上有一个OneToOne?典型的OneToOne不是这样设置的。延迟加载是一种设计模式,用于尽可能推迟对象的初始化,通常用于获取列表。使用Hibernate,当用户尝试获取资源时,事务通常会关闭。我建议删除Lazy 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);
});
楚皓君
2023-03-14

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

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

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

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

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

您有多种选择。

>

但是,您可能会考虑使用一种既搜索所有用户又创建响应的服务方法。您可能希望将@Transactional放在这个方法上。

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

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

 类似资料:
  • 问题内容: 经常出现在Python模块中。即使阅读了Python的文档,我也不明白它的用途以及使用时间/方式。 有人可以举例说明吗? 关于我收到的基本用法的一些答案似乎是正确的。 但是,我需要了解有关工作原理的另一件事: 对我来说,最令人困惑的概念是当前的python版本如何包含未来版本的功能,以及如何使用当前版本的Python成功地编译使用未来版本的功能的程序。 我猜想当前版本包含了将来的潜在功

  • 何时扩展RecyclerView.Adapter以及它是如何工作的? 我理解一段代码有困难。有人能解释一下这个方法什么时候扩展,它是用来做什么的吗?

  • 我想了解Spring Batch是如何进行事务管理的。这不是一个技术问题,而是一个概念性的问题:Spring Batch使用什么方法?这种方法的后果是什么? 让我试着澄清一下这个问题。例如,在TaskletStep中,我看到步骤执行通常如下所示: 准备步骤元数据的几个JobRepository事务 每一块要处理的业务事务 更多JobRepository事务,用区块处理的结果更新步骤元数据 这似乎是

  • 问题内容: 我从事SQL的时间不长,但是我想我知道,通过将SQL语句包装在事务中可以完成所有语句,或者没有一个完成。这是我的问题。我有一个具有lineitem集合的订单对象。订单项与order.OrderId相关。我已经验证 所有ID都已设置并且正确, 但是当我尝试保存(插入)订单时,我得到 的INSERT语句与FOREIGN KEY约束“FK_OrderItemDetail_Order”冲突。

  • 在会话范围内具有一个简单的CDI bean,其中注入了一个实体管理器: 现在,当通过EL#{myBean.test插入}调用函数时,有两件事似乎很奇怪: 1)将@Transactional注释移动到方法创建(int)我得到: javax.persistence。TransactionRequiredException:JBAS011469:执行此操作需要事务(使用事务或扩展持久性上下文) 2) 改

  • 我有一个TF模型,它经过量化训练,冻结,用TOCO转换成tflite,现在我有了tflite HTML图形模型和json。 我可以看到,对于我的图中的每个张量,每个都有量化属性(min,max,scale,zero pt),我试图确定这些属性如何应用于每个张量。 例如,我理解量化数据的表示,并且我可以理解,采用量化权重/偏差,乘以比例并添加最小值会返回原始权重/偏差(几乎)。 我不明白的是: 为什