【问题标题】:Spring - @Transactional across multiple services and repositoriesSpring - 跨多个服务和存储库的@Transactional
【发布时间】:2020-01-17 19:26:22
【问题描述】:

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

我希望完成的是在我的服务上使用@Transactional 注释,以确保在删除记录时,如果发生错误,无论是数据库还是业务逻辑异常,从事务中删除的任何记录都会回滚到其原始记录删除开始前的状态。

我希望交易开始的服务是MasterSpecService,并像这样调用其他服务:

deleteMasterSpec(MasterSpec masterSpec) {
     this.approvalTargetService.deleteApprovalTargetsForSpec(masterSpec.getSysI());
     this.approvalToleranceService.deleteApprovalTolerancesForSpec(masterSpec.getSysI());
     this.receivingToleranceService.deleteReceivingTolerancesForSpec(masterSpec.getSysI());
     this.finishedGoodTargetService.deleteFinishedGoodTargetsForSpec(masterSpec.getSysI());
     this.finishedGoodToleranceService.deleteFinishedGoodTolerancesForSpec(masterSpec.getSysI());
     this.maxValueService.deleteMaxValuesForSpec(masterSpec.getSysI());
     this.ingredientService.deleteSpecIngredients(masterSpec.getSysI());
     this.masterSpecRepo.deleteById(masterSpec.getSysI()); 
     // throw some exception here as a test, and have all the deletes rollback
}

在数据库中,目标表、公差表、最大值表和成分表都有对 MasterSpec 表的外键引用,所以我最后删除了 MasterSpec。

我希望MasterSpecService 成为主要事务,并让所有其他服务将自己附加到该事务,因此如果有任何失败,它将恢复。所有服务都有自己的 JPA 存储库来处理删除。

这可以通过@Transactional 注释来完成吗?

或者,当我在 MasterSpec 记录上调用 delete 时,如果事务的任何部分失败,是否会在我的各种 Entity 类中使​​用 @OneToMany 和 @ManyToOne 映射来完成相同的任务并恢复任何已删除的记录?,

【问题讨论】:

  • 我认为@Transactional 可以通过将deleteMasterSpec () 保持为公共方法并从另一个服务调用它来实现。

标签: hibernate spring-boot spring-data-jpa spring-transactions


【解决方案1】:

经过更多的挖掘,更合适的方法是我在问题末尾提到的,在我的类上使用带有@OneToOne、@OneToMany 和@ManyToOne 注释的双向映射。

在我的实体类 PMasterSpec.java 中,我添加了:

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "masterSpec")
private PApprovalTarget approvalTarget;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "masterSpec")
private PApprovalTolerance approvalTolerance;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "masterSpec")
private PReceivingTolerance receivingTolerance;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "masterSpec")
private PFinishedGoodTarget finishedGoodTarget;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "masterSpec")
private PFinishedGoodTolerance finishedGoodTolerance;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "masterSpec")
private PMaxValue maxValue;

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "masterSpec")
private List<PIngredient> ingredients;

而在PApprovalTarget、PApprovalTolerance、PReceivingTolerance、PFinishedGoodTarget、PFinishedGoodTolerance、PMaxValue实体类中,我通过外键映射回PMasterSpec类:

@OneToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "BOM_SPEC_SYS_I")
private PMasterSpec masterSpec;

在 PIngredient 类中:

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "BOM_SPEC_SYS_I", insertable = false, updatable = false)
private PMasterSpec masterSpec;

我的 MasterSpecService 仍被标记为事务性:

@Transactional(propagation = Propagation.REQUIRED)

但所有其他服务都不是。

现在,只要我构建 PMasterSpec 对象并提供所有其他嵌套实体类,当我调用 masterspecRepo.save(masterSpec) 时,它将创建一个事务来保存所有实体对象,并在保存或删除时回滚所有内容发生。

我遵循了这些例子:

Spring Boot JPA One to Many Mapping

Spring Boot JPA One to One Mapping

【讨论】:

    猜你喜欢
    • 2017-12-27
    • 2018-08-03
    • 2019-02-11
    • 2022-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    • 1970-01-01
    相关资源
    最近更新 更多