spring jdbc 源码 分析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

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

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

1 如何获得连接
看DataSourceUtils代码

Java代码

20191102100583\_1.png

  1. protectedstatic Connection doGetConnection(DataSource dataSource, boolean allowSynchronization);
  2. throws SQLException {
  3. ConnectionHolder conHolder = (ConnectionHolder); TransactionSynchronizationManager.getResource(dataSource);;
  4. if (conHolder != null); {
  5. conHolder.requested();;
  6. return conHolder.getConnection();;
  7. }
  8. Connection con = dataSource.getConnection();;
  9. if (allowSynchronization && TransactionSynchronizationManager.isSynchronizationActive();); {
  10. conHolder = new ConnectionHolder(con);;
  11. TransactionSynchronizationManager.bindResource(dataSource, conHolder);;
  12. TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(conHolder, dataSource););;
  13. conHolder.requested();;
  14. }
  15. return con;
  16. }
    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代码

20191102100583\_2.png

  1. privatestatic ThreadLocal resources = new ThreadLocal();;
  2. publicstatic Object getResource(Object key); {
  3. Map map = (Map); resources.get();;
  4. if (map == null); {
  5. returnnull;
  6. }
  7. Object value = map.get(key);;
  8. return value;
  9. }
  10. publicstaticvoid 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代码

20191102100583\_3.png

  1. publicvoid requested(); {
  2. this.referenceCount++;
  3. }
  4. publicvoid released(); {
  5. this.referenceCount–;
  6. }
    public void requested(); {
            this.referenceCount++;
        }

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

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

Java代码

20191102100583\_4.png

  1. if (conHolder != null); {
  2. conHolder.requested();;
  3. return conHolder.getConnection();;
  4. }
    if (conHolder != null); {
                conHolder.requested();;
                return conHolder.getConnection();;
            }

的原因

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

Java代码

20191102100583\_5.png

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

20191102100583\_6.png

  1. protectedstaticvoid doCloseConnectionIfNecessary(Connection con, DataSource dataSource); throws SQLException {
  2. if (con == null); {
  3. return;
  4. }
  5. ConnectionHolder conHolder = (ConnectionHolder); TransactionSynchronizationManager.getResource(dataSource);;
  6. if (conHolder != null && con == conHolder.getConnection();); {
  7. // It’s the transactional Connection: Don’t close it.
  8. conHolder.released();;
  9. return;
  10. }
  11. // Leave the Connection open only if the DataSource is our
  12. // special data source, and it wants the Connection left open.
  13. if (!(dataSource instanceof SmartDataSource); || ((SmartDataSource); dataSource);.shouldClose(con);); {
  14. logger.debug(“Closing JDBC connection”);;
  15. con.close();;
  16. }
  17. }
    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代码

20191102100583\_7.png

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

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

作用不言自明了吧

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

Java代码

20191102100583\_8.png

  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代码

20191102100583\_9.png

  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代码

20191102100583\_10.png

  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. returnnull;
  7. }
  8. }
    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,不如直接使用现成的。


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring jdbc 源码 分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏