spring的事務處理詳解:調用一個方法前的事務處理過程(源代碼分析)
?
?
實際上,在spring的事務中,只要該類被設置為了事務代理:
?
攔截器都會創建一個TransactionInfo 對象:
?
TransactionInfo txInfo = new TransactionInfo(txAttr, method);
?
?
而且如果
只要被調用的方法設置了事務屬性(txAttr),不管是什么屬性都會調用:
?
txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));
?
根據該方法的事務屬性(definition )的不同,this.transactionManager.getTransaction(txAttr)的返回值會有所不同(代碼見AbstractPlatformTransactionManager),具體為以下幾種情況:
1.當前沒有事務時(即以下代碼中的((HibernateTransactionObject) transaction).hasTransaction()返回false),會返回以下幾種:
?
?1
//
?Check?definition?settings?for?new?transaction.
?2
??
if
?(definition.getTimeout()?
<
?TransactionDefinition.TIMEOUT_DEFAULT)?
{
?3
???
throw
?
new
?InvalidTimeoutException(
"
Invalid?transaction?timeout
"
,?definition.getTimeout());
?4
??}
?5
?6
??
//
?No?existing?transaction?found?->?check?propagation?behavior?to?find?out?how?to?behave.
?7
??
if
?(definition.getPropagationBehavior()?
==
?TransactionDefinition.PROPAGATION_MANDATORY)?
{
?8
???
throw
?
new
?IllegalTransactionStateException(
?9
?????
"
Transaction?propagation?'mandatory'?but?no?existing?transaction?found
"
);
10
??}
11
??
else
?
if
?(definition.getPropagationBehavior()?
==
?TransactionDefinition.PROPAGATION_REQUIRED?
||
12
????definition.getPropagationBehavior()?
==
?TransactionDefinition.PROPAGATION_REQUIRES_NEW?
||
13
??????definition.getPropagationBehavior()?
==
?TransactionDefinition.PROPAGATION_NESTED)?
{
14
???
if
?(debugEnabled)?
{
15
????logger.debug(
"
Creating?new?transaction?with?name?[
"
?
+
?definition.getName()?
+
?
"
]
"
);
16
???}
17
???doBegin(transaction,?definition);
18
???
boolean
?newSynchronization?
=
?(
this
.transactionSynchronization?
!=
?SYNCHRONIZATION_NEVER);
19
???
return
?newTransactionStatus(definition,?transaction,?
true
,?newSynchronization,?debugEnabled,?
null
);
20
??}
21
??
else
?
{
22
???
//
?Create?"empty"?transaction:?no?actual?transaction,?but?potentially?synchronization.
23
???
boolean
?newSynchronization?
=
?(
this
.transactionSynchronization?
==
?SYNCHRONIZATION_ALWAYS);
24
???
return
?newTransactionStatus(definition,?
null
,?
false
,?newSynchronization,?debugEnabled,?
null
);
25
??}
26
2.當前有事務時
?1
private
?TransactionStatus?handleExistingTransaction(
?2
???TransactionDefinition?definition,?Object?transaction,?
boolean
?debugEnabled)
?3
???
throws
?TransactionException?
{
?4
?5
??
if
?(definition.getPropagationBehavior()?
==
?TransactionDefinition.PROPAGATION_NEVER)?
{
?6
???
throw
?
new
?IllegalTransactionStateException(
?7
?????
"
Transaction?propagation?'never'?but?existing?transaction?found
"
);
?8
??}
?9
10
??
if
?(definition.getPropagationBehavior()?
==
?TransactionDefinition.PROPAGATION_NOT_SUPPORTED)?
{
11
???
if
?(debugEnabled)?
{
12
????logger.debug(
"
Suspending?current?transaction
"
);
13
???}
14
???Object?suspendedResources?
=
?suspend(transaction);
15
???
boolean
?newSynchronization?
=
?(
this
.transactionSynchronization?
==
?SYNCHRONIZATION_ALWAYS);
16
???
return
?newTransactionStatus(
17
?????definition,?
null
,?
false
,?newSynchronization,?debugEnabled,?suspendedResources);
18
??}
19
20
??
if
?(definition.getPropagationBehavior()?
==
?TransactionDefinition.PROPAGATION_REQUIRES_NEW)?
{
21
???
if
?(debugEnabled)?
{
22
????logger.debug(
"
Suspending?current?transaction,?creating?new?transaction?with?name?[
"
?
+
23
??????definition.getName()?
+
?
"
]
"
);
24
???}
25
???Object?suspendedResources?
=
?suspend(transaction);
26
???doBegin(transaction,?definition);
27
???
boolean
?newSynchronization?
=
?(
this
.transactionSynchronization?
!=
?SYNCHRONIZATION_NEVER);
28
???
return
?newTransactionStatus(
29
?????definition,?transaction,?
true
,?newSynchronization,?debugEnabled,?suspendedResources);
30
??}
31
32
??
if
?(definition.getPropagationBehavior()?
==
?TransactionDefinition.PROPAGATION_NESTED)?
{
33
???
if
?(
!
isNestedTransactionAllowed())?
{
34
????
throw
?
new
?NestedTransactionNotSupportedException(
35
??????
"
Transaction?manager?does?not?allow?nested?transactions?by?default?-?
"
?
+
36
??????
"
specify?'nestedTransactionAllowed'?property?with?value?'true'
"
);
37
???}
38
???
if
?(debugEnabled)?
{
39
????logger.debug(
"
Creating?nested?transaction?with?name?[
"
?
+
?definition.getName()?
+
?
"
]
"
);
40
???}
41
???
if
?(useSavepointForNestedTransaction())?
{
42
????
//
?Create?savepoint?within?existing?Spring-managed?transaction,
43
????
//
?through?the?SavepointManager?API?implemented?by?TransactionStatus.
44
????
//
?Usually?uses?JDBC?3.0?savepoints.?Never?activates?Spring?synchronization.
45
????DefaultTransactionStatus?status?
=
46
??????newTransactionStatus(definition,?transaction,?
false
,?
false
,?debugEnabled,?
null
);
47
????status.createAndHoldSavepoint();
48
????
return
?status;
49
???}
50
???
else
?
{
51
????
//
?Nested?transaction?through?nested?begin?and?commit/rollback?calls.
52
????
//
?Usually?only?for?JTA:?Spring?synchronization?might?get?activated?here
53
????
//
?in?case?of?a?pre-existing?JTA?transaction.
54
????doBegin(transaction,?definition);
55
????
boolean
?newSynchronization?
=
?(
this
.transactionSynchronization?
!=
?SYNCHRONIZATION_NEVER);
56
????
return
?newTransactionStatus(definition,?transaction,?
true
,?newSynchronization,?debugEnabled,?
null
);
57
???}
58
??}
59
最后,txInfo被綁定到當前線程上作為當前事務:
?
txInfo.bindToThread()
?
然后,調用實際的目標類的方法并捕捉異常:
?
try
?
{
???
//
?This?is?an?around?advice.
???
//
?Invoke?the?next?interceptor?in?the?chain.
???
//
?This?will?normally?result?in?a?target?object?being?invoked.
???retVal?
=
?invocation.proceed();
??}
??
catch
?(Throwable?ex)?
{
???
//
?target?invocation?exception
???doCloseTransactionAfterThrowing(txInfo,?ex);
???
throw
?ex;
??}
??
finally
?
{
???doFinally(txInfo);
??}
??doCommitTransactionAfterReturning(txInfo);
??
return
?retVal;
?}

另外一點,TransactionInfo的newTransactionStatus調用時如果參數的不是null,TransactionInfo.hasTransaction()方法返回true;
?
重要提示:
在spring中創建的事務代理類并是目標類的超類,只是一個實現這目標類接口的類,該類會調用目標類的方法,所在如果一個目標類中的方法調用自身的另一個事務方法,另一個方法只是作為普通方法來調用,并不會加入事務機制
參考資料:
1.Spring Reference Manual:http://static.springframework.org/spring/docs/1.2.x/reference/index.html
2.Spring API doc:http://static.springframework.org/spring/docs/1.2.x/api/index.html
3.Spring 的源代碼
作者簡介:
????施祖陽,網名sylilzy,1979年生。
????2002年起從事軟件開發工作,主要研究為JAVA、Linux及相關技術。
?
?
?