2011-05-18 77 views
2

我有一个方法调用链,其中A调用B调用C调用D.A和D具有@Transactional注释。但B和C没有。这种情况下交易界限的范围是什么。是B和C部分的交易吗?Spring事务边界扩展

+0

a)A,B,C,D在同一班级吗? b)您是否使用JDK代理(默认),CGLib(proxy-target-class = true)或AspectJ(mode = aspectj) – 2011-05-18 14:54:19

+0

否,它们处于不同的类别中。我使用默认配置的Spring。 – meisam 2011-05-18 16:02:36

+0

re默认配置:这取决于你的类是否支持接口。他们? – 2011-05-18 17:12:06

回答

5

默认情况下,A,B,C & D在同一事务中工作。事务的默认传播级别是TX_REQUIRED,意思是如果一个新事务不存在(A开始一个,B,C,D参与),则开始一个新事务。

D可以通过将传播级别设置为TX_REQUIRES_NEW(如果您的环境支持它)来启动新事务。在这种情况下,当D完成时,恢复暂停的事务。提交D不会影响事务A的结果。回滚A不会回滚D(已提交),因为它们是单独的事务。

此外,很多开发人员忘记只有公有方法可能被标记为@Transactional,因为Spring使用代理来管理事务(私有/受保护的方法在“this”上被调用 - 因此代理没有机会去做它的魔法)。如果使用字节码注入而不是代理,这并不是必需的。

如果你想了解更多关于交易设计模式,我强烈建议下面的电子书(免费! - 需要注册):http://www.infoq.com/minibooks/JTDS。这是一个非常简单的阅读。

3

这取决于@Transactional注释的propagation参数。

默认情况下,A内发生的所有事情都是单个事务的一部分 - 包括直接或间接调用的所有方法。

其他传播模式将允许D暂停当前事务并自行启动,在嵌套事务中执行,或抛出异常,因为它并不意味着在现有事务中使用。

+0

我的意思是,当B和C没有任何注释时,是否应用默认的“需要”或...? – meisam 2011-05-18 14:58:43

+0

在事务设计中有一条“简单”的经验规则:启动事务的对象/方法也负责确定结果(提交/回滚)。在你的情况下,A在A完成之前调用B - > C - > D,因此它们参与A的事务。由于B&C没有注释,因此它们不是交易意识。 D有点不同,默认情况下它会检查是否有活动事务并参与。否则,它会开始一个新的。 – 2011-05-18 15:06:33

+1

@meisam:你看错了方向。事务不知道方法,而只知道如何访问事务感知资源,如数据库。该注释使A在执行事务之前启动一个事务,之后每次访问该线程中发生的事务感知资源(无论在哪种方法中)都是事务的一部分,直到A完成并提交或回退事务为止。 – 2011-05-18 15:34:07

2

独立的会发生什么:

,如果这个问题甚至出现时,你可能有严重的设计问题。

在95%的情况下,事务划分应该在应用程序的入口点进行,即在内部调用所有其他代码的服务方法中。

唯一有效的情况下,我可以想到@Transactional方法调用另一个方法时,内部方法有传播REQUIRES_NEW。如果不是这样:重构您的设计,以便您的代码只通过一个@Transactional注释。

+0

我同意100%。内部方法可能需要@Transactional的另一种情况是检查事务处于活动状态(TRX_MANDATORY):如果未找到任何异常,则会引发异常。我们在DAO上执行此操作,因此您无法直接调用DAO,必须通过服务层(REQUIRES_NEW | REQUIRED)。 – 2011-05-18 15:09:29

+0

@Patrick我同意TRX_MANDATORY,这是唯一的TX注释是有道理的一个DAO – 2011-05-18 15:12:04

+0

我不同意。如果C向队列添加任务会怎么样?那个任务实际上执行D?在这种情况下,您不能在同一个事务中使用它们,并且您需要为D使用REQUIRES_NEW,尽管这不像调用DAO方法那样直接。 – meisam 2011-05-18 16:06:39