【问题标题】:Spring Boot - Hibernate, Rollback successful save upon exceptionSpring Boot - 休眠,回滚成功保存异常
【发布时间】:2020-01-19 20:51:41
【问题描述】:

我正在使用 Spring Boot v2.1.3.RELEASE 和 Hibernate v5.3.6 构建应用程序。

之前,我问过一个关于如何在多个服务/存储库中使用 @Transactional 回滚的问题。通过将我的实体与 @OneToOne 和 @OneToMany 注释链接在一起,我得到了我需要的东西。

现在我面临一个新问题。在单个服务的函数中,我保存了两个单独的实体列表。一个列表保存,而另一个列表由于违反唯一键约束而失败。由于我正在测试,这预计会失败。

但是,我还没有想出如何用@Transactional注释我的服务或方法,这样当第二个列表保存失败时,它也会回滚第一个列表的任何成功保存。

例如:

@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
protected void saveLists() {
    List<Object> list1 = this.repository.getListOne();
    List<Object> list2 = this.repository.getListTwo();

    //Loop through list one and do some manipulation
    //Loop through list two and do some manipulation

    this.repository.saveAll(list1); // this saves all successfully
    this.repository.saveAll(list2); // this has unique key exception

    // rollback both list1 and list2 changes
}

在上面的例子中,list1中的数据被成功保存并在list2中抛出异常后出现在数据库中。

我认为由于它们使用相同的服务和相同的方法,使用相同的存储库,因此它们将使用相同的事务,并且 Hibernate 不会提交事务,直到它离开此方法且没有错误。

但情况似乎并非如此。由于列表一的数据正在提交而不是回滚。

我对@Transactional 注释有什么遗漏吗? 在任一保存引发错误时,如何使两个保存作为单个事务工作并回滚?

【问题讨论】:

  • 该方法最初是私有的,因为我不希望任何人直接从服务外部调用此方法。 Spring 不允许您将 @Transactional 放在私有方法上。它必须是公共的、受保护的或包私有的。我认为这不会有什么不同,因为我认为事务将在调用该函数时开始,并在函数完成时提交。
  • @NathanHughes 所以,如果说,我在调用服务的 Controller 端点上放了 @Transactional 注释,那么事务行为会启动吗?还是应该用@Transactional 注释我的JPA Repository 类?
  • 我想一个快速的解决方案是,而不是执行两个保存操作,将两个列表合并为一个并一次保存一个列表。然后,如果任何记录失败,则整个事务应该回滚。但这并不能帮助我理解为什么我当前的实现不起作用。

标签: java spring hibernate spring-boot spring-transactions


【解决方案1】:

您好 @Transactional 不适用于私有或受保护方法,您的方法应该是公共的。 为什么? 因为spring应该创建一个代理来处理事务的划分和行为。由于无法代理受保护或私有方法,因此您的注释只是忽略。

【讨论】:

    【解决方案2】:

    您只需要使用@Transactional 注释在控制器中调用的服务方法而不是此方法。 或者您可以使用 @Transactional 注释 Service 类

    【讨论】:

      猜你喜欢
      • 2011-12-16
      • 2013-08-18
      • 2010-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多