Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 为什么OpenEntityManagerInViewFilter会更改@事务传播需要新的行为?_Spring_Hibernate_Spring Mvc_Jpa_Spring Data Jpa - Fatal编程技术网

Spring 为什么OpenEntityManagerInViewFilter会更改@事务传播需要新的行为?

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

使用Spring 4.3.12、Spring数据JPA 1.11.8和Hibernate 5.2.12

我们使用
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:/";
  }
}