The Out-of-the-state features of spring's declarative transactions provide a great deal of convenience to users, and in most cases we use their declarative transactions when using spring. Declarative transactions involve the unified management of the spring framework for transaction processing, as well as the processing of concurrent transaction and transaction attributes, which is a more complex process, with a look at the concrete implementation of the spring framework declarative transaction capabilities.
first, the creation of a transaction
In the previous article on the source analysis of the spring transaction Interceptor Transactioninterceptor callback method invoke, we learned that before transaction processing, First, the transaction information object is created from the following two methods, based on whether it is a Callbackpreferringplatformtransactionmanager type of transaction processor:
Transactioninfo txinfo = Createtransactionifnecessary (tm, Txattr, joinpointidentification);
Transactioninfo txinfo = Preparetransactioninfo (tm, Txattr, joinpointidentification, status);
second, the transaction hangs
If there is a transaction in the current thread, but the transaction propagation attribute requires that a new transaction be opened, the existing transaction needs to be suspended, and the transaction's suspension involves the preservation of the thread and transaction information, and the source code is as follows:
Protected final Suspendedresourcesholder Suspend (Object transaction) throws TransactionException {//If the transaction is active, and the current thread transaction synchronization mechanism is also the activation state if (transactionsynchronizationmanager.issynchronizationactive ()) {//Suspend all synchronized transactions in the current thread List<tran
sactionsynchronization> suspendedsynchronizations = Dosuspendsynchronization ();
try {Object suspendedresources = null;
The operation of the suspend transaction is referred to the specific transaction processor if (transaction!= null) {suspendedresources = Dosuspend (transaction);
///thread to save information about the transaction and reset String name = Transactionsynchronizationmanager.getcurrenttransactionname () to the thread local variable in the thread.
Resets the thread local variable transactionsynchronizationmanager.setcurrenttransactionname (NULL) associated with the transaction in the current thread;
Boolean readOnly = Transactionsynchronizationmanager.iscurrenttransactionreadonly ();
Transactionsynchronizationmanager.setcurrenttransactionreadonly (FALSE);
Integer IsolationLevel = Transactionsynchronizationmanager.getcurrenttransactionisolationlevel (); Transactionsynchronizationmanager.setcurrenttransActionisolationlevel (NULL);
Boolean wasactive = Transactionsynchronizationmanager.isactualtransactionactive ();
Transactionsynchronizationmanager.setactualtransactionactive (FALSE); Saves transaction-related information in the current thread to the new Suspendedresourcesholder (Suspendedresources, suspendedsynchronizations, name, Reado
nly, IsolationLevel, wasactive);
A handling catch (RuntimeException ex) {doresumesynchronization (suspendedsynchronizations) that generated exceptions and errors in the transaction pending operation;
Throw ex;
catch (Error err) {doresumesynchronization (suspendedsynchronizations);
throw err; }//If a transaction is active, but the transaction synchronization mechanism is not active, only the transaction state needs to be saved, not//need to reset the thread-related local variable of the transaction else if (transaction!= null) {Object Suspendedresou
RCEs = Dosuspend (transaction);
return new Suspendedresourcesholder (suspendedresources);
}//Transaction and transaction synchronization mechanisms are not activated, do not want to handle else {return null;
}
}
iii. submission of the transaction
After the transaction method is successfully processed, the current transaction needs to be committed and the changes synchronized to the database, and the implementation source of the transaction commits is as follows:
Public final void commit (Transactionstatus status) throws TransactionException {//If the execution state of the transaction has ended, throw an exception if (Status.isco Mpleted ()) {throw new Illegaltransactionstateexception ("Transaction is already completed-do don't call commit or
Rollback more than once per transaction ");
} defaulttransactionstatus Defstatus = (defaulttransactionstatus) status; Rollback if (defstatus.islocalrollbackonly ()) {if (Defstatus.isdebug ()) {logger.debug ("Transactional Code") if the transaction is executing state
has requested rollback ");
}//Process transaction rollback processrollback (defstatus);
Return ///If the transaction is not marked as a rollback, the global rollback if (!shouldcommitonglobalrollbackonly () && defstatus.isglobalrollbackonly ()) of the transaction state {if (Defstatus.isdebug ()) {Logger.debug ("Global transaction is marked as Rollback-only but code transactional
uested commit ");
}//Rollback processing processrollback (defstatus); If the transaction state is in a new transaction, or if the global rollback fails if (status.isnewtransaction () | | isfailearlyonglobalrollbackonly ()) {throw-UnexPectedrollbackexception ("Transaction rolled back because it has been marked as rollback-only");
} return;
}//Processing submitted processcommit (defstatus); }//Commit processing operation private void Processcommit (Defaulttransactionstatus status) throws TransactionException {try {Boolean
beforecompletioninvoked = false;
try {//Transaction commit preparation, with specific transaction processor complete prepareforcommit (status);
Triggerbeforecommit (status);
Triggerbeforecompletion (status);
Beforecompletioninvoked = true;
Boolean globalrollbackonly = false; If the transaction state is a new transaction, or the global rollback failure if (status.isnewtransaction () | | isfailearlyonglobalrollbackonly ()) {//Set the transaction global rollback Globa
Lrollbackonly = Status.isglobalrollbackonly (); }//Nested transaction if (Status.hassavepoint ()) {if (Status.isdebug ()) {Logger.debug ("Releasing Transaction sav
Epoint ");
//Release suspend transaction save Point Status.releaseheldsavepoint (); //If the current transaction is a new transaction else if (Status.isnewtransaction ()) {if (Status.isdebug ()) {LoGger.debug ("Initiating transaction commit");
//Call the specific transaction processor to commit the transaction docommit (status); //If the transaction is marked as global rollback if (globalrollbackonly) {throw new Unexpectedrollbackexception ("Transaction silentl
Y rolled back because it has been marked as rollback-only "); An unexpected rollback exception was generated during the commit process, rollback processing catch (Unexpectedrollbackexception ex) {triggeraftercompletion (status, Transacti
Onsynchronization.status_rolled_back);
Throw ex;
////Transaction exception handling catch (TransactionException ex) {//If rollback fails, rollback exception handling if (Isrollbackoncommitfailure ()) {
Dorollbackoncommitexception (status, ex);
else {triggeraftercompletion (status, Transactionsynchronization.status_unknown);
} throw ex; ///exception handling catch (RuntimeException ex) {//if not called before completion of the IF (!beforecompletioninvoked) {//trigger back before completion
The method of triggerbeforecompletion (status);
//Rollback exception handling dorollbackoncommitexception (status, ex);
Throw ex;The error handling catch (Error err) {if (!beforecompletioninvoked) {triggerbeforecompletion) (status) generated during the commit process;
} dorollbackoncommitexception (status, Err);
throw err;
The callback action after the commit is triggered try {triggeraftercommit (status);
Finally {triggeraftercompletion (status, transactionsynchronization.status_committed);
Clears the transaction-related state after the commit completes finally {cleanupaftercompletion (status);
}
}
iv. rollback of the transaction
When an exception is generated during a transaction, or when a commit fails, it is often necessary to roll back the existing changes in the database, that is, to revert to the state before the operation, and to rollback the implementation code as follows:
Public final void rollback (Transactionstatus status) throws TransactionException {//If the transaction state is complete, throw an exception if (Status.iscomp Leted ()) {throw new Illegaltransactionstateexception ("Transaction is already completed-do don't call commit or R
Ollback more than once per transaction ");
} defaulttransactionstatus Defstatus = (defaulttransactionstatus) status;
Handling the rollback operation Processrollback (Defstatus); }//Rollback operation private void Processrollback (Defaulttransactionstatus status) {The callback operation before the completion of the try {try {///trigger TRIGGERBEF
Orecompletion (status); Nested transaction rollback processing if (Status.hassavepoint ()) {if (Status.isdebug ()) {Logger.debug ("rolling back transaction to S
AvePoint ");
//Rollback suspend transaction status.rollbacktoheldsavepoint at SavePoint (); The rollback operation of the new transaction in the current transaction else if (Status.isnewtransaction ()) {if (Status.isdebug ()) {Logger.debug ("Initiat
ing transaction rollback ");
}//Rollback processing, implemented by the specific transaction processor Dorollback (status); //If there are no new transactions in the current transaction else if (Status.hastransaction ()) {//If the current transaction state is local rollback, or global rollback failure if (status.islocalrollbackonly () | | isglobalrollbackonpa Rticipationfailure ()) {if (Status.isdebug ()) {Logger.debug ("Participating Transaction Failed-ma
Rking existing transaction as rollback-only ");
//Set the current transaction state to rollback dosetrollbackonly (status); }//The current transaction state is not set to a local rollback and no global rollback fails, then//the rollback is handled by the previous transaction in the thread, any processing else {if (Status.isdebug ()) {logger.
Debug ("Participating Transaction failed-letting transaction originator decide on rollback"); }///If the current thread has no transaction else {logger.debug ("Should Roll back transaction but Cannot-no transaction Ava
Ilable "); }//Handle catch (RuntimeException ex) {triggeraftercompletion for run-time exceptions and errors during rollback operations (status, Transactionsynchroniz ation.
Status_unknown);
Throw ex;
catch (Error err) {triggeraftercompletion (status, Transactionsynchronization.status_unknown); ThroW err;
After the rollback operation is completed, the callback Operation Triggeraftercompletion (status, Transactionsynchronization.status_rolled_back) after triggering the rollback;
//Purge transaction state information after rollback finally {cleanupaftercompletion (status);
}
}