Spring ConnectionHolder

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的代理。

其次,想使用Spring事物,又不想对Spring进行依赖是不可能的。与其试图自己模拟DataSourceUtils,不如直接使用现成的。



http://blog.sina.com.cn/s/blog_53dd74430100haaj.html


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值