轉自:
http://www.iteye.com/topic/11738前幾天解釋了Spring的抽象事務機制。這次講講Spring中的DataSource 事務。
DataSource事務相關的類比較多,我們一步步來撥開其中的密團。
1 如何獲得連接
看DataSourceUtils代碼
- protected static Connection doGetConnection(DataSource dataSource, boolean allowSynchronization);
- throws SQLException {
-
- ConnectionHolder conHolder = (ConnectionHolder); TransactionSynchronizationManager.getResource(dataSource);;
- if (conHolder != null); {
- conHolder.requested();;
- return conHolder.getConnection();;
- }
-
-
- Connection con = dataSource.getConnection();;
- if (allowSynchronization && TransactionSynchronizationManager.isSynchronizationActive();); {
- conHolder = new ConnectionHolder(con);;
- TransactionSynchronizationManager.bindResource(dataSource, conHolder);;
- TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(conHolder, dataSource););;
- conHolder.requested();;
- }
-
- return con;
- }
protected static Connection doGetConnection(DataSource dataSource, boolean allowSynchronization);
throws SQLException {
ConnectionHolder conHolder = (ConnectionHolder); TransactionSynchronizationManager.getResource(dataSource);;
if (conHolder != null); {
conHolder.requested();;
return conHolder.getConnection();;
}
Connection con = dataSource.getConnection();;
if (allowSynchronization && TransactionSynchronizationManager.isSynchronizationActive();); {
conHolder = new ConnectionHolder(con);;
TransactionSynchronizationManager.bindResource(dataSource, conHolder);;
TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(conHolder, dataSource););;
conHolder.requested();;
}
return con;
}
原來連接是從TransactionSynchronizationManager中獲取,如果TransactionSynchronizationManager中已經有了,那么拿過來然后調用conHolder.requested()。否則從原始的DataSource這創建一個連接,放到一個ConnectionHolder,然后再調用TransactionSynchronizationManager.bindResource綁定。
好,我們又遇到兩個新的類TransactionSynchronizationManager和ConnectionHolder和。繼續跟蹤
2 TransactionSynchronizationManager
看其中的一些代碼
- private static ThreadLocal resources = new ThreadLocal();;
- public static Object getResource(Object key); {
- Map map = (Map); resources.get();;
- if (map == null); {
- return null;
- }
- Object value = map.get(key);;
- return value;
- }
- public static void bindResource(Object key, Object value); throws IllegalStateException {
- Map map = (Map); resources.get();;
- if (map == null); {
- map = new HashMap();;
- resources.set(map);;
- }
- map.put(key, value);;
- }
private static ThreadLocal resources = new ThreadLocal();;
public static Object getResource(Object key); {
Map map = (Map); resources.get();;
if (map == null); {
return null;
}
Object value = map.get(key);;
return value;
}
public static void bindResource(Object key, Object value); throws IllegalStateException {
Map map = (Map); resources.get();;
if (map == null); {
map = new HashMap();;
resources.set(map);;
}
map.put(key, value);;
}
原來TransactionSynchronizationManager內部建立了一個ThreadLocal的resources,這個resources又是和一個map聯系在一起的,這個map在某個線程第一次調用bindResource時生成。
聯系前面的DataSourceUtils代碼,我們可以總結出來。
某個線程使用DataSourceUtils,當第一次要求創建連接將在TransactionSynchronizationManager中創建出一個ThreadLocal的map。然后以DataSource作為鍵,ConnectionHolder為值放到map中。等這個線程下一次再請求的這個DataSource的時候,就從這個map中獲取對應的ConnectionHolder。用map是為了解決同一個線程上多個DataSource。
然后我們來看看ConnectionHolder又是什么?
3 對連接進行引用計數
看ConnectionHolder代碼,這個類很簡單,看不出個所以然,只好再去看父類代碼ResourceHolderSupport,我們感興趣的是這兩個方法
- public void requested(); {
- this.referenceCount++;
- }
-
- public void released(); {
- this.referenceCount--;
- }
public void requested(); {
this.referenceCount++;
}
public void released(); {
this.referenceCount--;
}
看得出這是一個引用計數的技巧。原來Spring中對Connection是竟量使用已創建的對象,而不是每次都創建一個新對象。這就是DataSourceUtils中
- if (conHolder != null); {
- conHolder.requested();;
- return conHolder.getConnection();;
- }
if (conHolder != null); {
conHolder.requested();;
return conHolder.getConnection();;
}
的原因
4 釋放連接
完成事物后DataSourceTransactionManager有這樣的代碼
- protected void doCleanupAfterCompletion(Object transaction); {
- DataSourceTransactionObject txObject = (DataSourceTransactionObject); transaction;
-
-
- TransactionSynchronizationManager.unbindResource(this.dataSource);;
- txObject.getConnectionHolder();.clear();;
-
-
- }
protected void doCleanupAfterCompletion(Object transaction); {
DataSourceTransactionObject txObject = (DataSourceTransactionObject); transaction;
// Remove the connection holder from the thread.
TransactionSynchronizationManager.unbindResource(this.dataSource);;
txObject.getConnectionHolder();.clear();;
//... DataSourceUtils.closeConnectionIfNecessary(con, this.dataSource);;
}
DataSourceUtils
- protected static void doCloseConnectionIfNecessary(Connection con, DataSource dataSource); throws SQLException {
- if (con == null); {
- return;
- }
-
- ConnectionHolder conHolder = (ConnectionHolder); TransactionSynchronizationManager.getResource(dataSource);;
- if (conHolder != null && con == conHolder.getConnection();); {
-
- conHolder.released();;
- return;
- }
-
-
-
- if (!(dataSource instanceof SmartDataSource); || ((SmartDataSource); dataSource);.shouldClose(con);); {
- logger.debug("Closing JDBC connection");;
- con.close();;
- }
- }
protected static void doCloseConnectionIfNecessary(Connection con, DataSource dataSource); throws SQLException {
if (con == null); {
return;
}
ConnectionHolder conHolder = (ConnectionHolder); TransactionSynchronizationManager.getResource(dataSource);;
if (conHolder != null && con == conHolder.getConnection();); {
// It's the transactional Connection: Don't close it.
conHolder.released();;
return;
}
// Leave the Connection open only if the DataSource is our
// special data source, and it wants the Connection left open.
if (!(dataSource instanceof SmartDataSource); || ((SmartDataSource); dataSource);.shouldClose(con);); {
logger.debug("Closing JDBC connection");;
con.close();;
}
}
恍然大悟。如果事物完成,那么就
TransactionSynchronizationManager.unbindResource(this.dataSource);將當前的ConnectionHolder
從TransactionSynchronizationManager上脫離,然后doCloseConnectionIfNecessary。最后會把連接關閉掉。
5 兩個輔助類JdbcTemplate和TransactionAwareDataSourceProxy
JdbcTemplate中的execute方法的第一句和最后一句
- public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action);
- throws DataAccessException {
-
- Connection con = DataSourceUtils.getConnection(getDataSource(););;
-
- DataSourceUtils.closeConnectionIfNecessary(con, getDataSource(););;
- }
- }
public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action);
throws DataAccessException {
Connection con = DataSourceUtils.getConnection(getDataSource(););;
//其他代碼
DataSourceUtils.closeConnectionIfNecessary(con, getDataSource(););;
}
}
作用不言自明了吧
從TransactionAwareDataSourceProxy中獲取的連接是這個樣子的
- public Connection getConnection(); throws SQLException {
- Connection con = DataSourceUtils.doGetConnection(getTargetDataSource();, true);;
- return getTransactionAwareConnectionProxy(con, getTargetDataSource(););;
- }
public Connection getConnection(); throws SQLException {
Connection con = DataSourceUtils.doGetConnection(getTargetDataSource();, true);;
return getTransactionAwareConnectionProxy(con, getTargetDataSource(););;
}
萬變不離其宗,不過我們還是看看getTransactionAwareConnectionProxy
- protected Connection getTransactionAwareConnectionProxy(Connection target, DataSource dataSource); {
- return (Connection); Proxy.newProxyInstance(
- ConnectionProxy.class.getClassLoader();,
- new Class[] {ConnectionProxy.class},
- new TransactionAwareInvocationHandler(target, dataSource););;
- }
protected Connection getTransactionAwareConnectionProxy(Connection target, DataSource dataSource); {
return (Connection); Proxy.newProxyInstance(
ConnectionProxy.class.getClassLoader();,
new Class[] {ConnectionProxy.class},
new TransactionAwareInvocationHandler(target, dataSource););;
}
原來返回的是jdk的動態代理。繼續看TransactionAwareInvocationHandler
- public Object invoke(Object proxy, Method method, Object[] args); throws Throwable {
-
- if (this.dataSource != null); {
- DataSourceUtils.doCloseConnectionIfNecessary(this.target, this.dataSource);;
- }
- return null;
- }
-
- }
public Object invoke(Object proxy, Method method, Object[] args); throws Throwable {
//... if (method.getName();.equals(CONNECTION_CLOSE_METHOD_NAME);); {
if (this.dataSource != null); {
DataSourceUtils.doCloseConnectionIfNecessary(this.target, this.dataSource);;
}
return null;
}
}
TransactionAwareDataSourceProxy會先從DataSourceUtils獲取連接。然后將這個連接用jdk的動態代理包一下返回。外部代碼如果調用的這個冒牌的Connection,就會先調用TransactionAwareInvocationHandler的invoke,在這個invoke 中,完成原來調用DataSourceUtils的功能。
總結上面的流程
Spring 對DataSource進行事務管理的關鍵在于ConnectionHolder和TransactionSynchronizationManager。
0.先從TransactionSynchronizationManager中嘗試獲取連接
1.如果前一步失敗則在每個線程上,對每個DataSouce只創建一個Connection
2.這個Connection用ConnectionHolder包裝起來,由TransactionSynchronizationManager管理
3.再次請求同一個連接的時候,從TransactionSynchronizationManager返回已經創建的ConnectionHolder,然后調用ConnectionHolder的request將引用計數+1
4.釋放連接時要調用ConnectionHolder的released,將引用計數-1
5.當事物完成后,將ConnectionHolder從TransactionSynchronizationManager中解除。當誰都不用,這個連接被close
以上所有都是可以調用DataSourceUtils化簡代碼,而JdbcTemplate又是調用DataSourceUtils的。所以在Spring文檔中要求盡量首先使用JdbcTemplate,其次是用DataSourceUtils來獲取和釋放連接。至于TransactionAwareDataSourceProxy,那是下策的下策。不過可以將Spring事務管理和遺留代碼無縫集成。
所以如某位朋友說要使用Spring的事務管理,但是又不想用JdbcTemplate,那么可以考慮TransactionAwareDataSourceProxy。這個類是原來DataSource的代理。
其次,想使用Spring事物,又不想對Spring進行依賴是不可能的。與其試圖自己模擬DataSourceUtils,不如直接使用現成的。