【问题标题】:Forcing different Spring Repositories to use the same transaction强制不同的 Spring Repositories 使用相同的事务
【发布时间】:2018-10-02 16:26:08
【问题描述】:

我正在做一个项目,我想使用一个非常具体的事务传播策略。该数据库有两组表,活动表和存档表。每组表都使用自己的扩展CrudRepository<T, ID> 的实体和接口实现。目标是将一组实体插入到活动表中,并将活动表中的所有数据在单个事务中插入到存档表中。表中的实体是不相同的,并且会有不同的表结构。

给定两个类似于表单的独立存储库

public interface FooRepository extends CrudRepository<Foo, Integer>
public interface FooArchiveRepository extends CrudRepository<FooArchive, Integer>

和类似的实现

@Autowired FooRepository fooRepo;
@Autowired FooArchiveRepository fooArchiveRepo;
@Autowired BarService barService;
List<Foo> newData = barService.doThing();
fooRepo.saveAll(newData);
// fooData is a list of FooArchive from earlier
fooArchiveRepo.saveAll(fooData);

目标是保证fooRepo.saveAll(newData)fooArchiveRepo.saveAll(fooData) 在单个数据库事务中执行。 Spring 的 Required 默认事务传播在同一物理事务中执行不同的 Transactional 方法 - 这适用于应用程序上下文中的所有 Transactional 方法,还是仅适用于每个实体?

【问题讨论】:

  • 即使它们有不同的表结构,考虑before update trigger(假设数据库支持它)。当多种类型的客户端可以更新时,这可以简化客户端并降低复杂性。

标签: java spring spring-boot spring-data-jpa


【解决方案1】:

将保存调用包装到一个新方法中并用@Transactional注释该方法

@Transactional
public void saveAll(){
  fooRepo.saveAll(newData);
  // fooData is a list of FooArchive from earlier
  fooArchiveRepo.saveAll(fooData);
}

默认情况下(PROPAGATION_REQUIRED)它会将内部事务执行到同一个事务中。请参见 https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/images/tx_prop_required.png

【讨论】:

  • 读了之后感觉很明显,谢谢!你知道我如何验证或测试交易传播吗?
  • 您可以创建一个 SpringBootTest 并使用方法 saveAll() 自动装配服务。通过添加约束使您的第二次保存失败(例如,您可以在字段上添加 @NotNull 并尝试将其保存为空值以强制失败)。之后,您可以断言第一次保存的数据没有更新。
  • 拥有多个事务对性能的影响是什么
  • 对于这种情况,不是性能影响的问题,而是事务原子性的问题。目标是如果将数据添加到一个表的事务失败,则另一个表不应该添加数据。如果两组表交互都发生在一次提交中,那么就达到了这个目标。
  • 我没有得到您提到的相同行为。正如你提到的,我已经分离到 saveAll() 。但是在控制台中,我注意到每个 repo 保存都有不同的事务。有什么想法吗?
猜你喜欢
  • 2022-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多