理解Spring事务 - 当一个事务方法调用另一个事务方法时会发生什么?

28

为了理解Spring事务的工作原理,我想知道在以下情况下会发生什么,其中一个方法被标记为@Transactional ,并调用另一个被标记为@Transactional 的方法。

假设配置使用所有默认设置。

@Service("myService")
@Transactional
public MyService{
   public void myServiceMethod(){
      myDAO.getSomeDBObjects();
   }
}

@Repository("myDAO")
@Transactional
public MyDAOWithUsesBeyondMyService{
   public void getSomeDBObjects(){...}
}

假设我输入MyService.myServiceMethod(),显然它会开启一个事务。那么,当我进入myDAO.getSomeDBObjects()时会发生什么?因为已经存在一个事务,所以不会创建新的事务吗?还是我在这里创建了两个事务?

关于传播性的文档(下面引用)似乎涵盖了这一点,但我想验证一下我的理解,毕竟对于我这个无知的脑袋来说有点难以理解全部内容。

传播性:通常,在事务范围内执行的所有代码都将在该事务中运行。但是,您可以选择指定当在事务上下文已经存在时执行事务方法的行为。例如,代码可以继续在现有事务中运行(常见情况),或者暂停现有事务并创建一个新事务。Spring提供了EJB CMT熟悉的所有事务传播选项。有关Spring中事务传播语义的详细信息,请参见第10.5.7节“事务传播”。

1个回答

40

两个答案:

a) 不要这样做。在服务层或DAO层中使用@Transactional,但不要同时使用(通常选择服务层,因为您可能需要每个服务方法一个事务)。

b) 如果你这样做,会发生什么取决于@Transactional注释的传播属性,并在这个部分描述:10.5.7 事务传播。基本上:PROPAGATION_REQUIRED表示两个方法将使用相同的事务,而PROPAGATION_REQUIRES_NEW则启动一个新事务。

关于你的评论:

当然我继续阅读并意识到,由于我使用代理,因此第二种方法不会由事务代理管理,因此它像任何其他方法调用一样。

在您的情况下,这不是真的(只有如果两个方法都在同一个类中)。

如果一个bean有方法ab,并且a调用了b,那么b是在实际方法上调用的,而不是代理,因为它是从代理内部调用的(bean不知道它被代理到外部世界)。

proxy      bean  
a() -->    a()
            |
            V  
b() -->    b()

然而在你的情况下,一个服务将会拥有一个被注入的DAO对象,这个对象本身就是一个代理,因此你会面对这样一种情况:

           proxy      bean
service    a() -->    a()
                       |
             /---------/
             |                 
             V
dao        b() -->    b()

谢谢,是的,我并不打算这样做,但当我意识到我在服务类级别声明了 @Transactional,并且服务的一个方法调用了另一个方法(两者都是事务性的)时,这个问题突然浮现在脑海中。当然,我继续阅读并意识到,由于我使用代理,因此这个第二个方法不会被事务代理管理,因此它就像任何其他方法调用一样(这足以使一个新手的大脑混乱)。 :) 但这让我很好奇,以确保我理解所有工作原理的细节,你已经为我澄清了这一点。谢谢! - David Parks
@David,我觉得你对代理概念有些误解。请阅读我的更新。 - Sean Patrick Floyd
你说得完全正确,我的评论是错误的(实际上我没有说明就改变了假设),但我理解你的意思,并且在所有这些之后,我认为整件事现在已经深深植根于我的脑海中了。感谢更新和精彩的图表,我相信许多其他人将来会发现它在他们的搜索中非常有用! - David Parks
@SeanPatrickFloyd,您能否请看一下http://stackoverflow.com/questions/31784818/why-transaction-here-is-treated-as-two-separate-transactions并提供您的专业建议? - emilly

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