spring jdbc 源码 分析

 

Collections.unmodifiableMap(map)-------------------------返回一个不可修改的map

 

转自:http://www.iteye.com/topic/11738

1 如何获得连接
看DataSourceUtils代码

Java代码 复制代码  收藏代码
  1. protected static Connection doGetConnection(DataSource dataSource, boolean allowSynchronization);   
  2.             throws SQLException {   
  3.            
  4.         ConnectionHolder conHolder = (ConnectionHolder); TransactionSynchronizationManager.getResource(dataSource);;   
  5.         if (conHolder != null); {   
  6.             conHolder.requested();;   
  7.             return conHolder.getConnection();;   
  8.         }   
  9.   
  10.            
  11.         Connection con = dataSource.getConnection();;   
  12.         if (allowSynchronization && TransactionSynchronizationManager.isSynchronizationActive();); {   
  13.                         conHolder = new ConnectionHolder(con);;   
  14.             TransactionSynchronizationManager.bindResource(dataSource, conHolder);;   
  15.             TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(conHolder, dataSource););;   
  16.             conHolder.requested();;   
  17.         }   
  18.   
  19.         return con;   
  20.     }  
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
看其中的一些代码

Java代码 复制代码  收藏代码
  1. private static ThreadLocal resources = new ThreadLocal();;   
  2. public static Object getResource(Object key); {   
  3.         Map map = (Map); resources.get();;   
  4.         if (map == null); {   
  5.             return null;   
  6.         }   
  7.         Object value = map.get(key);;   
  8.                 return value;   
  9.     }   
  10. public static void bindResource(Object key, Object value); throws IllegalStateException {   
  11.         Map map = (Map); resources.get();;   
  12.                 if (map == null); {   
  13.             map = new HashMap();;   
  14.             resources.set(map);;   
  15.         }   
  16.         map.put(key, value);;   
  17.             }  
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,我们感兴趣的是这两个方法

Java代码 复制代码  收藏代码
  1. public void requested(); {   
  2.         this.referenceCount++;   
  3.     }   
  4.   
  5.     public void released(); {   
  6.         this.referenceCount--;   
  7.     }  
public void requested(); {
		this.referenceCount++;
	}

	public void released(); {
		this.referenceCount--;
	}


看得出这是一个引用计数的技巧。原来Spring中对Connection是竟量使用已创建的对象,而不是每次都创建一个新对象。这就是DataSourceUtils中

Java代码 复制代码  收藏代码
  1. if (conHolder != null); {   
  2.             conHolder.requested();;   
  3.             return conHolder.getConnection();;   
  4.         }  
if (conHolder != null); {
			conHolder.requested();;
			return conHolder.getConnection();;
		}

的原因


4 释放连接
完成事物后DataSourceTransactionManager有这样的代码

Java代码 复制代码  收藏代码
  1. protected void doCleanupAfterCompletion(Object transaction); {   
  2.         DataSourceTransactionObject txObject = (DataSourceTransactionObject); transaction;   
  3.   
  4.         // Remove the connection holder from the thread.   
  5.         TransactionSynchronizationManager.unbindResource(this.dataSource);;   
  6.         txObject.getConnectionHolder();.clear();;   
  7.   
  8.         //...       DataSourceUtils.closeConnectionIfNecessary(con, this.dataSource);;   
  9.     }  
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

Java代码 复制代码  收藏代码
  1. protected static void doCloseConnectionIfNecessary(Connection con, DataSource dataSource); throws SQLException {   
  2.         if (con == null); {   
  3.             return;   
  4.         }   
  5.   
  6.         ConnectionHolder conHolder = (ConnectionHolder); TransactionSynchronizationManager.getResource(dataSource);;   
  7.         if (conHolder != null && con == conHolder.getConnection();); {   
  8.             // It's the transactional Connection: Don't close it.   
  9.             conHolder.released();;   
  10.             return;   
  11.         }   
  12.            
  13.         // Leave the Connection open only if the DataSource is our   
  14.         // special data source, and it wants the Connection left open.   
  15.         if (!(dataSource instanceof SmartDataSource); || ((SmartDataSource); dataSource);.shouldClose(con);); {   
  16.             logger.debug("Closing JDBC connection");;   
  17.             con.close();;   
  18.         }   
  19.     }  
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方法的第一句和最后一句

Java代码 复制代码  收藏代码
  1. public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action);   
  2.             throws DataAccessException {   
  3.   
  4.         Connection con = DataSourceUtils.getConnection(getDataSource(););;   
  5.         //其他代码   
  6.     DataSourceUtils.closeConnectionIfNecessary(con, getDataSource(););;   
  7.         }   
  8.     }  
public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action);
			throws DataAccessException {

		Connection con = DataSourceUtils.getConnection(getDataSource(););;
		//其他代码
	DataSourceUtils.closeConnectionIfNecessary(con, getDataSource(););;
		}
	}


作用不言自明了吧

从TransactionAwareDataSourceProxy中获取的连接是这个样子的

Java代码 复制代码  收藏代码
  1. public Connection getConnection(); throws SQLException {   
  2.         Connection con = DataSourceUtils.doGetConnection(getTargetDataSource();, true);;   
  3.         return getTransactionAwareConnectionProxy(con, getTargetDataSource(););;   
  4.     }  
public Connection getConnection(); throws SQLException {
		Connection con = DataSourceUtils.doGetConnection(getTargetDataSource();, true);;
		return getTransactionAwareConnectionProxy(con, getTargetDataSource(););;
	}


万变不离其宗,不过我们还是看看getTransactionAwareConnectionProxy

Java代码 复制代码  收藏代码
  1. protected Connection getTransactionAwareConnectionProxy(Connection target, DataSource dataSource); {   
  2.         return (Connection); Proxy.newProxyInstance(   
  3.                 ConnectionProxy.class.getClassLoader();,   
  4.                 new Class[] {ConnectionProxy.class},   
  5.                 new TransactionAwareInvocationHandler(target, dataSource););;   
  6.     }  
protected Connection getTransactionAwareConnectionProxy(Connection target, DataSource dataSource); {
		return (Connection); Proxy.newProxyInstance(
				ConnectionProxy.class.getClassLoader();,
				new Class[] {ConnectionProxy.class},
				new TransactionAwareInvocationHandler(target, dataSource););;
	}


原来返回的是jdk的动态代理。继续看TransactionAwareInvocationHandler

Java代码 复制代码  收藏代码
  1. public Object invoke(Object proxy, Method method, Object[] args); throws Throwable {   
  2.         //...           if (method.getName();.equals(CONNECTION_CLOSE_METHOD_NAME);); {   
  3.                 if (this.dataSource != null); {   
  4.                     DataSourceUtils.doCloseConnectionIfNecessary(this.target, this.dataSource);;   
  5.                 }   
  6.                 return null;   
  7.             }   
  8.   
  9.                     }  
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,不如直接使用现成的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值