Spring 事務(wù)管理創(chuàng)造性的解決了很多以前要用重量級的應用服務(wù)器才能解決的事務(wù)問題,那么其實現(xiàn)原理一定很深奧吧?可是如果讀者仔細研究了Spring事務(wù)管理的代碼以后就會發(fā)現(xiàn),事務(wù)管理其實也是如此簡單的事情。這也印證了在本書開頭的一句話“重劍無鋒、大巧不工”,Spring并沒有使用什么特殊的API,它運行的原理就是事務(wù)的原理。下面是DataSourceTransactionManager的啟動事務(wù)用的代碼(經(jīng)簡化):
protected void doBegin(Object transaction, TransactionDefinition definition)
{
?DataSourceTransactionObject txObject =
(DataSourceTransactionObject) transaction;
?Connection con = null;
?try
?{
??if (txObject.getConnectionHolder() == null)
??{
???Connection newCon = this.dataSource.getConnection();
???txObject.setConnectionHolder(
new ConnectionHolder(newCon), true);
??}
??txObject.getConnectionHolder()
.setSynchronizedWithTransaction(true);
??con = txObject.getConnectionHolder().getConnection();
??Integer previousIsolationLevel = DataSourceUtils
?????.prepareConnectionForTransaction(con, definition);
??txObject.setPreviousIsolationLevel(previousIsolationLevel);
??if (con.getAutoCommit())
??{
???txObject.setMustRestoreAutoCommit(true);
???con.setAutoCommit(false);
??}
??txObject.getConnectionHolder().setTransactionActive(true);
??// Bind the session holder to the thread.
??if (txObject.isNewConnectionHolder())
??{
???TransactionSynchronizationManager.bindResource(
getDataSource(),txObject.getConnectionHolder());
??}
?}
?catch (SQLException ex)
?{
??DataSourceUtils.releaseConnection(con, this.dataSource);
??throw new CannotCreateTransactionException(
?????"Could not open JDBC Connection for transaction", ex);
?}
}
本文出自:http://www.cownew.com
在調(diào)用一個需要事務(wù)的組件的時候,管理器首先判斷當前調(diào)用(即當前線程)有沒有一個事務(wù),如果沒有事務(wù)則啟動一個事務(wù),并把事務(wù)與當前線程綁定。Spring使用TransactionSynchronizationManager的bindResource方法將當前線程與一個事務(wù)綁定,采用的方式就是ThreadLocal,這可以從TransactionSynchronizationManager類的代碼看出。
public abstract class TransactionSynchronizationManager
{
?……
?private static final ThreadLocal currentTransactionName = new ThreadLocal();
?private static final ThreadLocal currentTransactionReadOnly = new ThreadLocal();
?private static final ThreadLocal actualTransactionActive = new ThreadLocal();?……
}
從doBegin的代碼中可以看到在啟動事務(wù)的時候,如果Connection是的自動提交的(也就是getAutoCommit()方法返回true)則事務(wù)管理就會失效,所以首先要調(diào)用setAutoCommit(false)方法將其改為非自動提交的。setAutoCommit(false)這個動作在有的JDBC驅(qū)動中會非常耗時,所以最好在配置數(shù)據(jù)源的時候就將“autoCommit”屬性配置為true。