Spring 为什么OpenEntityManagerInViewFilter会更改@事务传播需要新的行为?
使用Spring 4.3.12、Spring数据JPA 1.11.8和Hibernate 5.2.12 我们使用Spring 为什么OpenEntityManagerInViewFilter会更改@事务传播需要新的行为?,spring,hibernate,spring-mvc,jpa,spring-data-jpa,Spring,Hibernate,Spring Mvc,Jpa,Spring Data Jpa,使用Spring 4.3.12、Spring数据JPA 1.11.8和Hibernate 5.2.12 我们使用OpenEntityManagerInViewFilter确保实体加载后,实体关系不会引发lazyiinitializationexception。在我们的控制器中,我们通常使用一个带注释的@modeldattribute方法按id加载实体,并使加载的实体可用于控制器的请求映射处理程序方法 在某些情况下,如审计,我们需要提交实体修改,即使其他事务可能出错并回滚。因此,我们使用@Tran
OpenEntityManagerInViewFilter
确保实体加载后,实体关系不会引发lazyiinitializationexception
。在我们的控制器中,我们通常使用一个带注释的@modeldattribute
方法按id加载实体,并使加载的实体可用于控制器的请求映射处理程序方法
在某些情况下,如审计,我们需要提交实体修改,即使其他事务可能出错并回滚。因此,我们使用@Transactional(propagation=propagation.REQUIRES_NEW)
注释我们的审计工作,以确保此事务将成功提交,而不管是否有其他可能成功完成的事务(如果有)
我在使用openEntityManagerViewFilter
的实践中看到,当传播时,需要\u NEW
事务尝试提交在新事务范围之外发生的更改,这会导致工作始终导致成功提交到数据库,而不是回滚
例子
鉴于此Spring数据,JPA支持的存储库(类似地定义了EmployeeRepository
):
该控制器:
@Controller
public class StackOverflowQuestionController {
private final EmployeeRepository employeeRepository;
private final MethodAuditor methodAuditor;
public StackOverflowQuestionController(EmployeeRepository employeeRepository, MethodAuditor methodAuditor) {
this.employeeRepository = employeeRepository;
this.methodAuditor = methodAuditor;
}
@ModelAttribute
public Employee loadEmployee(@RequestParam Long id) {
return employeeRepository.findOne(id);
}
@GetMapping("/updateEmployee")
// @Transactional // <-- When uncommented, transactions work as expected (using OpenEntityManagerInViewFilter or not)
public String updateEmployee(@ModelAttribute Employee employee, RedirectAttributes ra) {
// method auditor performs work in new transaction
methodAuditor.auditMethod("updateEmployee"); // <-- at close of this method, employee update occurrs trigging rollback
// No code after this point executes
System.out.println(employee.getPin());
employeeRepository.save(employee);
return "redirect:/";
}
}
@控制器
公共类StackOverflowController{
私人最终雇员安置所雇员安置所;
私人最终审计师;
公共堆栈溢出问题控制器(EmployeeRepository EmployeeRepository,MethodAuditor MethodAuditor){
this.employeeRepository=employeeRepository;
this.methodAuditor=methodAuditor;
}
@模型属性
public Employee loadEmployee(@RequestParam Long id){
返回employeeRepository.findOne(id);
}
@GetMapping(“/updateEmployee”)
//@Transactional/在应用程序(服务器)运行时尝试进行两个单独的事务,您仍在使用单个EntityManager
和单个Datasource
,因此在任何给定时间JPA和数据库只会看到一个事务。因此,如果您希望将这些事务分开,则需要在应用程序运行时设置两个数据源和两个EntityManager
阳离子(服务器)尝试进行两个单独的事务您仍在使用单个EntityManager
和单个数据源
,因此在任何给定时间JPA和数据库只会看到一个事务。因此,如果您希望将这些事务分开,则需要设置两个数据源
和两个EntityManager
谢谢您的帮助回答。如果是这种情况,为什么将updateEmployee
方法注释为@Transaction
可以解决问题?是否需要在同一EntityManager
实例中使用新的事务来挂起当前事务,从而允许新事务以不受任何操作影响的方式运行ther transaction?我注意到javadoc上的注释:“实际的事务暂停不会在所有事务管理器上立即生效。这尤其适用于JtaTransactionManager,它要求javax.transaction.TransactionManager对其可用(在标准Java EE中是特定于服务器的)。”我在用谢谢你的回答。如果是这样的话,为什么将updateEmployee
方法注释为@Transaction
可以解决问题呢?不需要在同一EntityManager
实例中使用新的事务来挂起当前事务,从而允许新事务以如下方式运行不会受到任何其他事务的影响吗?我注意到javadoc上的注释:“实际事务暂停不会在所有事务管理器上立即生效。这尤其适用于JtaTransactionManager,它要求提供javax.transaction.TransactionManager(在标准JavaEE中是特定于服务器的)
@Service
public class MethodAuditorImpl implements MethodAuditor {
private final MethodAuditRepository methodAuditRepository;
public MethodAuditorImpl(MethodAuditRepository methodAuditRepository) {
this.methodAuditRepository = methodAuditRepository;
}
@Override @Transactional(propagation = Propagation.REQUIRES_NEW)
public void auditMethod(String methodName) {
MethodAudit audit = new MethodAudit();
audit.setMethodName(methodName);
audit.setInvocationTime(LocalDateTime.now());
methodAuditRepository.save(audit);
}
}
@Controller
public class StackOverflowQuestionController {
private final EmployeeRepository employeeRepository;
private final MethodAuditor methodAuditor;
public StackOverflowQuestionController(EmployeeRepository employeeRepository, MethodAuditor methodAuditor) {
this.employeeRepository = employeeRepository;
this.methodAuditor = methodAuditor;
}
@ModelAttribute
public Employee loadEmployee(@RequestParam Long id) {
return employeeRepository.findOne(id);
}
@GetMapping("/updateEmployee")
// @Transactional // <-- When uncommented, transactions work as expected (using OpenEntityManagerInViewFilter or not)
public String updateEmployee(@ModelAttribute Employee employee, RedirectAttributes ra) {
// method auditor performs work in new transaction
methodAuditor.auditMethod("updateEmployee"); // <-- at close of this method, employee update occurrs trigging rollback
// No code after this point executes
System.out.println(employee.getPin());
employeeRepository.save(employee);
return "redirect:/";
}
}