<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-314  評論-209  文章-0  trackbacks-0
    轉自:http://www.iteye.com/topic/11738
    前幾天解釋了Spring的抽象事務機制。這次講講Spring中的DataSource 事務。
    DataSource事務相關的類比較多,我們一步步來撥開其中的密團。

    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.     }  

    原來連接是從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.             }  
    原來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.     }  

    看得出這是一個引用計數的技巧。原來Spring中對Connection是竟量使用已創建的對象,而不是每次都創建一個新對象。這就是DataSourceUtils中
    Java代碼 復制代碼 收藏代碼
    1. if (conHolder != null); {   
    2.             conHolder.requested();;   
    3.             return conHolder.getConnection();;   
    4.         }  
    的原因


    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.     }  

    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.     }  

    恍然大悟。如果事物完成,那么就
    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.     }  

    作用不言自明了吧

    從TransactionAwareDataSourceProxy中獲取的連接是這個樣子的
    Java代碼 復制代碼 收藏代碼
    1. public Connection getConnection(); throws SQLException {   
    2.         Connection con = DataSourceUtils.doGetConnection(getTargetDataSource();, true);;   
    3.         return getTransactionAwareConnectionProxy(con, getTargetDataSource(););;   
    4.     }  

    萬變不離其宗,不過我們還是看看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.     }  

    原來返回的是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.                     }  

    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,不如直接使用現成的。
    posted on 2011-08-09 14:59 xzc 閱讀(4008) 評論(1)  編輯  收藏 所屬分類: Spring

    評論:
    # re: Spring事務管理與數據庫連接 2014-06-18 22:52 | zuidaima
    主站蜘蛛池模板: 99热亚洲色精品国产88| 国产性爱在线观看亚洲黄色一级片 | 亚洲va无码专区国产乱码| 国产国拍亚洲精品福利 | 国产精品亚洲成在人线| 亚洲一区AV无码少妇电影☆| 久久久久一级精品亚洲国产成人综合AV区| 亚洲AⅤ视频一区二区三区| 日韩精品电影一区亚洲| 亚洲欧洲自拍拍偷精品 美利坚| 亚洲精品国产综合久久一线| 国产精品亚洲综合一区| 国产精品亚洲精品日韩已满| 亚洲激情在线观看| 亚洲最新黄色网址| 亚洲日产乱码一二三区别| 国产亚洲精品美女2020久久| 一本久久免费视频| 在线成人精品国产区免费| 精品无码国产污污污免费网站| 四虎免费影院ww4164h| 免费无码又黄又爽又刺激| 日本不卡免费新一二三区| 免费成人av电影| 国产亚洲综合成人91精品| 97久久精品亚洲中文字幕无码| 亚洲国产品综合人成综合网站| 亚洲综合无码一区二区痴汉| 国产99久久亚洲综合精品| a级毛片毛片免费观看永久| 最近中文字幕mv免费高清视频8| 一本无码人妻在中文字幕免费 | 久久精品视频免费看| 免费三级毛片电影片| 国产一级一片免费播放| 亚洲综合伊人久久大杳蕉| 亚洲免费视频在线观看| 亚洲爆乳精品无码一区二区| 久草免费福利在线| 97人妻无码一区二区精品免费| 国产男女猛烈无遮挡免费视频网站 |