一个应用程序中可以有多个Spring @Transactional注释吗?

4
在我的应用程序中,我有几个不同方法上的@Transactional注释。它们使用Crud Repository在数据库上执行删除操作。我想知道这些删除操作是在什么阶段执行的,是否需要所有@Transactional注释?
例如,在一个façade方法中调用了2个删除方法,然后在runner中调用了facade方法: 1. 方法 1:
@Transactional
public void deleteFromSchemaOne(){

}

1. 方法2:

@Transactional
public void deleteFromSchemaTwo(){

}

2. 在外观方法中调用这两个方法:

@Transacational
public void deleteFromAllSchemas(){

deleteFromSchemaOne();
deleteFromSchemaTwo();

}

3. 在运行器中调用外观方法

@Transactional
    public void run(String... args) throws Exception {

        service.deleteFromAllSchemas();


}

我想知道的是:

我的删除操作实际上将在哪个阶段被执行?是在Runner方法完成时吗?

编辑:

带有循环的Facade方法:

public void deleteFromAllSchemas() {

    for(int i = 0; i < list.size(); i++){

     deleteFromSchemaOne();
     deleteFromSchemaTwo();

    }

}

1个回答

4
当最外层的事务完成后,也就是在run()之后。 实际上它并不是最外层的事务,而是唯一的事务。内部的@Transactionals不会创建新的事务,它们只是加入现有的事务。
如果你需要确保某些更改在最外层事务完成之前提交,你需要使用@Transactional(propagation=Propagation.REQUIRES_NEW)设置事务的传播方式。即使已经存在一个事务,这也将创建一个新的事务。
在你的示例代码中(至少基于它当前包含的内容),run()方法可能甚至不应该开始一个事务。
如果我理解你的意思正确,你想要类似以下的东西:
public void run() {
    for(int i = 0;i < list.size(); i++)
        service.deleteFromAllSchemas(i);
}

@Transactional
public void deleteFromAllSchemas(int i) {
    deleteFromSchemaOne(i);
    deleteFromSchemaTwo(i);
}

基本上我想要做的是确保deleteFromAllSchemas()方法是事务性的,即模式一和模式二中的所有内容都必须被删除或根本不执行任何操作。我该如何做呢?谢谢您的帮助。 - java123999
1
这是通过在deleteFromAllSchemas()中使用@Transactional实现的。如果发生错误,它将回滚对deleteFromSchemaOne()deleteFromSchemaTwo()所做的任何更改。你真的应该了解一下事务处理。它们不是你可以只靠希望就能正确处理或者“边干边学”的东西。 - Kayaman
1
这是正确的。我想补充一下,通常情况下,事务应该尽可能短。因此,除非这些数据库删除操作彼此依赖(比如说如果其中一个失败,你希望回滚整个事务),否则你应该只注释这两个删除方法。这样可以确保每个删除都在单独的事务中运行。如果它们确实相互依赖,请注释调用它们的方法,并可选地使用@Transactional(propagation=Propagation.MANDATORY)注释删除方法。 - tkralik
@java123999 这个问题太宽泛了,很难讨论。也许永远不会出现,也许取决于你的设计在某些情况下会出现。 - Kayaman
你真正无法控制 JPA 实现查询的执行时间。但是当调用外观方法时,事务开始并在方法返回时提交/回滚。但是为什么要在外观方法中启动事务?对我来说似乎是一种反模式。 - tkralik
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接