Spring事务,connection获取,用DataSourceUtils的原理
来源:互联网 发布:深圳淘宝推广培训 编辑:程序博客网 时间:2024/06/03 16:50
前几天解释了Spring的抽象事务机制。这次讲讲Spring中的DataSource 事务。
DataSource事务相关的类比较多,我们一步步来拨开其中的密团。
1 如何获得连接 看DataSourceUtils代码
Java代码
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代码
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代码
public void requested(); { this.referenceCount++; } public void released(); { this.referenceCount--; }
看得出这是一个引用计数的技巧。原来Spring中对Connection是竟量使用已创建的对象,而不是每次都创建一个新对象。这就是DataSourceUtils中 的原因
Java代码
if (conHolder != null); { conHolder.requested();; return conHolder.getConnection();; }
4 释放连接 完成事物后DataSourceTransactionManager有这样的代码
DataSourceUtils
Java代码
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); } 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代码
public Object execute(PreparedStatementCreator psc,PreparedStatementCallback action); throws DataAccessException { Connection con = DataSourceUtils.getConnection(getDataSource()); //其他代码 DataSourceUtils.closeConnectionIfNecessary(con, getDataSource()); } }
作用不言自明了吧
从TransactionAwareDataSourceProxy中获取的连接是这个样子的
Java代码
public Connection getConnection() throws SQLException { Connection con = DataSourceUtils.doGetConnection(getTargetDataSource(), true); return getTransactionAwareConnectionProxy(con, getTargetDataSource()); }
万变不离其宗,不过我们还是看看getTransactionAwareConnectionProxy
Java代码
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代码
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。
先从TransactionSynchronizationManager中尝试获取连接
如果前一步失败则在每个线程上,对每个DataSouce只创建一个Connection
这个Connection用ConnectionHolder包装起来,由TransactionSynchronizationManager管理再次请求同一个连接的时候,从TransactionSynchronizationManager返回已经创建的ConnectionHolder,然后调用ConnectionHolder的request将引用计数+1释放连接时要调用ConnectionHolder的released,将引用计数-1
当事物完成后,将ConnectionHolder从TransactionSynchronizationManager中解除。当谁都不用,这个连接被close
以上所有都是可以调用DataSourceUtils化简代码,而JdbcTemplate又是调用DataSourceUtils的。所以在Spring文档中要求尽量首先使用JdbcTemplate,其次是用DataSourceUtils来获取和释放连接。至于TransactionAwareDataSourceProxy,那是下策的下策。不过可以将Spring事务管理和遗留代码无缝集成。
所以如某位朋友说要使用Spring的事务管理,但是又不想用JdbcTemplate,那么可以考虑TransactionAwareDataSourceProxy。这个类是原来DataSource的代理。
其次,想使用Spring事物,又不想对Spring进行依赖是不可能的。与其试图自己模拟DataSourceUtils,不如直接使用现成的。
转载地址 http://yangleiol.iteye.com/blog/731694
- Spring事务,connection获取,用DataSourceUtils的原理
- Spring事务,connection获取,用DataSourceUtils的原理
- spring DataSourceUtils
- spring的事务原理
- spring事务 connection
- 事务的定义,事务的作用以及Spring事务原理
- 事务的定义,事务的作用以及Spring事务原理
- 事务的定义,事务的作用以及Spring事务原理
- 事务的定义,事务的作用以及Spring事务原理
- 事务的定义,事务的作用以及Spring事务原理
- Spring 获取Connection
- Spring中事务的实现原理
- Spring事务原理
- Spring事务原理
- Spring事务原理
- Spring事务原理
- Spring 事务代理原理
- Spring事务原理
- [转]GPU硬件结构
- 《Motion Design for iOS》(十九)
- Mybatis学习总结二
- java版本存储器管理LRU
- JAVA 实现身份证验证
- Spring事务,connection获取,用DataSourceUtils的原理
- 危险!在HashMap中将可变对象用作Key
- iOS获取设备方向(锁屏状态下通用)
- js判断一个对象数组里是否存在某个元素
- GCD的使用
- ftp服务怎么登陆
- 数据库之SQLite增删改查
- LeetCode 33. Search in Rotated Sorted Array(旋转数组搜索)
- Leetcode 97. Interleaving String