Spring中的DataSource 事务。
DataSource事务相关的类比较多 ,我们一步步来拨开其中的密团。
1 如何获得连接
看DataSourceUtils代码
java代码:
protected static Connection doGetConnection(DataSource dataSource, boolean allowSynchronization)
throws SQLException {
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizati
onManager.getResource(dataSource);
if (conHolder != null) {
conHolder.requested();
return conHolder.getConnection();
}
Connection con = dataSource.getConnection();
if (allowSynchronization
&& TransactionSynchronizati
onManager
.isSynchronizationActive
()) {
conHolder
= new ConnectionHolder
(con);
TransactionSynchronizati
onManager.bindResource
(dataSource
, conHolder);
TransactionSynchronizati
onManager.registerSynchronization(new ConnectionSynchronizatio
n(conHolder, dataSource));
conHolder.requested();
}
return con;
}
原来连接是从TransactionSynchronizati
onManager中获取,如果 TransactionSynchronizati
onManager中已经有了,那么拿过来然后调用conHolder.requested()。否则 从原始的DataSource这创建一个连接,放到一个ConnectionHolder,然后再调用 TransactionSynchronizati
onManager.bindResource绑定。
好,我们又遇到两个新的类TransactionSynchronizati
onManager和ConnectionHolder和。继续跟踪
2 TransactionSynchronizati
onManager
看其中的一些代码
java代码:
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);
}
原来TransactionSynchronizati
onManager内部建立了一个ThreadLocal的resources,这个resources又是和一个map联系在一起的,这个map在某个线程第一次调用bindResource时生成。
联系前面的DataSourceUtils代码,我们可以总结出来。
某个线程使用DataSourceUtils,当第一次要求创建连接将在TransactionSynchronizati
onManager中 创建出一个ThreadLocal的map。然后以DataSource作为键,ConnectionHolder为值放到map中。等这个线程下一次再 请求的这个DataSource的时候,就从这个map中获取对应的ConnectionHolder。用map是为了解决同一个线程上多个 DataSource。
然后我们来看看ConnectionHolder又是什么?
3 对连接进行引用计数
看ConnectionHolder代码,这个类很简单,看不出个所以然,只好再去看父类代码ResourceHolderSupport,我们感兴趣的是这两个方法
java代码:
public void requested() {
this.referenceCount++;
}
public void released() {
this.referenceCount--;
}
看得出这是一个引用计数的技巧。原来Spring中对Connection是竟量使用已创建的对象,而不是每次都创建一个新对象。这就是DataSourceUtils中 java代码:
if (conHolder != null) {
conHolder.requested();
return conHolder.getConnection();
}
的原因
4 释放连接
完成事物后DataSourceTransactionMan
ager有这样的代码
java代码:
protected void doCleanupAfterCompletion
(Object transaction) {
DataSourceTransactionObj
ect txObject = (DataSourceTransactionObj
ect) transaction;
// Remove the connection holder from the thread.
TransactionSynchronizati
onManager.unbindResource(this.dataSource);
txObject.getConnectionHolder().clear();
//...
DataSourceUtils.closeConnectionIfNecessa
ry(con, this.dataSource);
}
DataSourceUtils
java代码:
protected static void doCloseConnectionIfNeces
sary(Connection con, DataSource dataSource) throws SQLException {
if (con == null) {
return;
}
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizati
onManager.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();
}
}
恍然大悟。如果事物完成,那么就
TransactionSynchronizati
onManager.unbindResource(this.dataSource);将当前的ConnectionHolder
从TransactionSynchronizati
onManager上脱离,然后doCloseConnectionIfNeces
sary。最后会把连接关闭掉。
5 两个辅助类JdbcTemplate和TransactionAwareDataSour
ceProxy
JdbcTemplate中的execute方法的第一句和最后一句
java代码:
public Object execute(PreparedStatementCreator
psc, PreparedStatementCallbac
k action)
throws DataAccessException {
Connection con = DataSourceUtils.getConnection(getDataSource());
//其他代码
DataSourceUtils.closeConnectionIfNecessa
ry(con, getDataSource());
}
}
作用不言自明了吧
从TransactionAwareDataSour
ceProxy中获取的连接是这个样子的
java代码:
public Connection getConnection() throws SQLException {
Connection con = DataSourceUtils.doGetConnection(getTargetDataSource(), true);
return getTransactionAwareConne
ctionProxy(con, getTargetDataSource());
}
万变不离其宗,不过我们还是看看getTransactionAwareConne
ctionProxy
java代码:
protected Connection getTransactionAwareConne
ctionProxy(Connection target, DataSource dataSource) {
return (Connection) Proxy.newProxyInstance(
ConnectionProxy.class.getClassLoader(),
new Class[] {ConnectionProxy.class},
new TransactionAwareInvocati
onHandler(target, dataSource));
}
原来返回的是jdk的动态代理。继续看TransactionAwareInvocati
onHandler
java代码:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//...
if (method.getName().equals(CONNECTION_CLOSE_METHOD_NAME)) {
if (this.dataSource != null) {
DataSourceUtils.doCloseConnectionIfNeces
sary(this.target, this.dataSource);
}
return null;
}
}
TransactionAwareDataSour
ceProxy会先从DataSourceUtils获取连接。然后将这个连接用jdk的动态 代理包一下返回。外部代码如果调用的这个冒牌的Connection,就会先调用TransactionAwareInvocati
onHandler的 invoke,在这个invoke 中,完成原来调用DataSourceUtils的功能。
总结上面的流程
Spring 对DataSource进行事务管理的关键在于ConnectionHolder和TransactionSynchronizati
onManager。
0.先从TransactionSynchronizati
onManager中尝试获取连接
1.如果前一步失败则在每个线程上,对每个DataSouce只创建一个Connection
2.这个Connection用ConnectionHolder包装起来,由TransactionSynchronizati
onManager管理
3.再次请求同一个连接的时候,从TransactionSynchronizati
onManager返回已经创建的ConnectionHolder,然后调用ConnectionHolder的request将引用计数+1
4.释放连接时要调用ConnectionHolder的released,将引用计数-1
5.当事物完成后,将ConnectionHolder从TransactionSynchronizati
onManager中解除。当谁都不用,这个连接被close
以上所有都是可以调用DataSourceUtils化简代码,而JdbcTemplate又是调用DataSourceUtils的。所以在 Spring文档中要求尽量首先使用JdbcTemplate,其次是用DataSourceUtils来获取和释放连接。至于 TransactionAwareDataSour
ceProxy,那是下策的下策。不过可以将Spring事务管理和遗留代码无缝集成。
所以如某位朋友说要使用Spring的事务管理,但是又不想用JdbcTemplate,那么可以考虑TransactionAwareDataSour
ceProxy。这个类是原来DataSource的代理。
DataSource事务相关的类比较多 ,我们一步步来拨开其中的密团。
1 如何获得连接
看DataSourceUtils代码
java代码:
protected static Connection doGetConnection(DataSource dataSource, boolean allowSynchronization)
原来连接是从TransactionSynchronizati
好,我们又遇到两个新的类TransactionSynchronizati
2 TransactionSynchronizati
看其中的一些代码
java代码:
private static ThreadLocal resources = new ThreadLocal();
public static Object getResource(Object key) {
public static void bindResource(Object key, Object value) throws IllegalStateException {
原来TransactionSynchronizati
联系前面的DataSourceUtils代码,我们可以总结出来。
某个线程使用DataSourceUtils,当第一次要求创建连接将在TransactionSynchronizati
然后我们来看看ConnectionHolder又是什么?
3 对连接进行引用计数
看ConnectionHolder代码,这个类很简单,看不出个所以然,只好再去看父类代码ResourceHolderSupport,我们感兴趣的是这两个方法
java代码:
public void requested() {
看得出这是一个引用计数的技巧。原来Spring中对Connection是竟量使用已创建的对象,而不是每次都创建一个新对象。这就是DataSourceUtils中 java代码:
if (conHolder != null) {
的原因
4 释放连接
完成事物后DataSourceTransactionMan
java代码:
protected void doCleanupAfterCompletion
DataSourceUtils
java代码:
protected static void doCloseConnectionIfNeces
恍然大悟。如果事物完成,那么就
TransactionSynchronizati
从TransactionSynchronizati
5 两个辅助类JdbcTemplate和TransactionAwareDataSour
JdbcTemplate中的execute方法的第一句和最后一句
java代码:
public Object execute(PreparedStatementCreator
作用不言自明了吧
从TransactionAwareDataSour
java代码:
public Connection getConnection() throws SQLException {
万变不离其宗,不过我们还是看看getTransactionAwareConne
java代码:
protected Connection getTransactionAwareConne
原来返回的是jdk的动态代理。继续看TransactionAwareInvocati
java代码:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
TransactionAwareDataSour
总结上面的流程
Spring 对DataSource进行事务管理的关键在于ConnectionHolder和TransactionSynchronizati
0.先从TransactionSynchronizati
1.如果前一步失败则在每个线程上,对每个DataSouce只创建一个Connection
2.这个Connection用ConnectionHolder包装起来,由TransactionSynchronizati
3.再次请求同一个连接的时候,从TransactionSynchronizati
4.释放连接时要调用ConnectionHolder的released,将引用计数-1
5.当事物完成后,将ConnectionHolder从TransactionSynchronizati
以上所有都是可以调用DataSourceUtils化简代码,而JdbcTemplate又是调用DataSourceUtils的。所以在 Spring文档中要求尽量首先使用JdbcTemplate,其次是用DataSourceUtils来获取和释放连接。至于 TransactionAwareDataSour
所以如某位朋友说要使用Spring的事务管理,但是又不想用JdbcTemplate,那么可以考虑TransactionAwareDataSour
其次,想使用Spring事物,又不想对Spring进行依赖是不可能的。与其试图自己模拟DataSourceUtils,不如直接使用现成的。
http://blog.sina.com.cn/s/blog_53dd74430100haaj.html