<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      spring事務管理器設計思想(一)

      在最近做的一個項目里面,涉及到多數據源的操作,比較特殊的是,這多個數據庫的表結構完全相同,由于我們使用的ibatis框架作為持久化層,為了防止每一個數據源都配置一套規則,所以重新實現了數據源,根據線程變量中指定的數據庫連接名稱來獲取實際的數據源。

      一個簡單的實現如下:

      public class ProxyDataSource implements DataSource {
      /** 數據源池配置 */
      private Map<String, DataSource> dataSourcePoolConfig;
      
      public Connection getConnection() throws SQLException {
              return createDataSource().getConnection();
      }
      private synchronized DataSource createDataSource() {
              String dbName = DataSourceContextHolder.getDbName();
              return dataSourcePoolConfig.get(dbName);
      }

       

      每次調用spring事務管理器之前,設置DataSourceContextHolder.set(“dbName”) 

      事務提交之后在調用 DataSourceContextHolder.clear() 方法即可

       但是這樣設計實際使用過程中也會遇到一些典型的問題,這就是在仔細了解spring中持久化層的設計之后,才能明白所產生的問題的原因。下面主要總結一下spring 持久化的設計。

       

      Jdbc基本的編程模型

      由于任何持久化層的封裝實際上都是對java.sql.Connection等相關對象的操作,一個典型的數據操作的流程如下:

      但在我們實際使用spring和ibatis的時候,都沒有感覺到上面的流程,其實spring已經對外已經屏蔽了上述的操作,讓我們更關注業務邏輯功能,但是我們有必要了解其實現,以便能夠更好運用和定位問題。

       

      開啟事務:

      在開啟事務的時候,我們需要初始化事務上下文信息,以便在業務完成之后,需要知道事務的狀態,以便進行后續的處理,這個上下文信息可以保存在 ThreadLocal里面,包括是否已經開啟事務,事務的超時時間,隔離級別,傳播級別,是否設置為回滾。這個信息對應用來說是透明的,但是提供給使用者編程接口,以便告知業務結束的時候是提交事務還是回滾事務。

       

      獲取連接

      首先來看看spring如何獲取數據庫連接的,對于正常情況來看,獲取連接直接調用DataSource.getConnection()就可以了,我們在自己實現的時候也肯定會這么做,但是需要考慮兩種情況(這里面先不引入事務的傳播屬性):

      1 還沒有獲取過連接,這是第一次獲取連接

      2 已經獲取過連接,不是第一次獲取連接,可以復用連接

      解決獲取數據庫連接的關鍵問題就是如何判斷是否已經可用的連接,而不需要開啟新的數據庫連接,同時由于數據庫連接需要給后續的業務操作復用,如何保持這個連接,并且透明的傳遞給后續流程。對于一個簡單的實現就是使用線程上下文變量ThrealLocal來解決以上兩個問題。

      具體的實現是:在獲取數據庫連接的時候,判斷當前線程線程變量里面是否已經存在相關連接,如果不存在,就創新一個新的連接,如果存在,就直接獲取其對應的連接。在第一次獲取到數據庫連接的時候,我們還需要做一些特殊處理,就是設置自動提交為false。在業務活動結束的時候在進行提交或者回滾。這個時候就是要調用connection.setAutoCommit(false)方法。

       

      執行sql

      這一部分和業務邏輯相關,通過對外提供一些編程接口,可以讓業務決定業務完成之后如何處理事務,比較簡單的就是設置事務狀態。

       

      提交事務:

      在開啟事務的時候,事務上下文信息已經保存在線程變量里面了,可以根據事務上下文的信息,來決定是否是提交還是回滾。其實就是調用數據庫連接Connection.commit 和 Connection.rollback 方法。然后需要清空線程變量中的事務上下文信息。相當于結束了當前的事務。

        

      關閉連接:

      關閉連接相對比較簡單,由于當前線程變量保存了連接信息,只需要獲取連接之后,調用connection.close方法即可,接著清空線程變量的數據庫連接信息。

       上面幾個流程是一個簡單的事務處理流程,在spring中都有對應的實現,見TransactionTemplate.execute方法。Spring定義了一個TransactionSynchronizationManager對象,里面保存了各種線程變量信息,

       

      //保存了數據源和其對應連接的映射,value是一個Map結構,其中key為datasource,value為其打開的連接
      
      private static final ThreadLocal resources
      
      //這個暫時用不到,不解釋
      
      private static final ThreadLocal synchronizations
      
      //當前事務的名字
      
      private static final ThreadLocal currentTransactionName
      
      //是否是只讀事務以及事務的隔離級別(這個一般我們都用不到,都是默認界別)
      
      private static final ThreadLocal currentTransactionReadOnly
      
      private static final ThreadLocal currentTransactionIsolationLevel
      
      //代表是否是一個實際的事務活動,這個后面將)
      
      private static final ThreadLocal actualTransactionActive

       

      在獲取連接的時候,可見DataSourceUtils.doGetConnection()方法,就是從調用TransactionSynchronizationManager.getResource(dataSource)獲取連接信息,如果為空,就直接從調用dataSource.getConnection()創建新的連接,后面在調用

      TransactionSynchronizationManager.bindResource(dataSource,conn)綁定數據源到線程變量,以便后續的線程在使用。

      ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
      
                         if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
      
                                  conHolder.requested();
      
                                  if (!conHolder.hasConnection()) {
      
                                           logger.debug("Fetching resumed JDBC Connection from DataSource");
      
                                           conHolder.setConnection(dataSource.getConnection());
      
                                  }
      
                                  return conHolder.getConnection();
      
                         }
      
              
      
                         logger.debug("Fetching JDBC Connection from DataSource");
      
                         Connection con = dataSource.getConnection();

      在提交事務的時候,見 DataSourceTransactionManager.doCommit方法,其實就是獲取事務狀態信息以及連接信息,調用conn.commmit方法,比較簡單。

       

      但是實際上,spring事務管理遠遠比上述復雜,我們沒有考慮以下幾種情況:

      1 如果當前操作不需要事務支持,也就是每次執行一次,就自動進行提交。如何在同一個架構里面兼容這兩種情況。比如就是簡單的query操作。

      2 一個業務活動跨越多個事務,每個事務的傳播級別配置不一樣。后面會拿一個例子來說明

       

      對于第一個問題,比較好解決,首先就是根據線程變量里面獲取數據源對應的連接,如果有連接,就復用。如果沒有,就創建連接。在判斷當前是否存在活動的事務上下文,如果存在事務信息,設置conn.setAutoCommit(false),然后設置線程上下文,綁定對應的數據源。如果不存在事務信息,就直接返回連接給應用。

      這樣就會帶來一個新的問題,就是連接如何進行關閉。根據最開始的分析,在存在事務上下文的情況下,直接從獲取線程獲取對應的數據庫連接,然后關閉。在關閉的也需要也進行判斷一下即可。在spring里面,在事務中獲取連接和關閉連接有一些特殊的處理,主要還是和其jdbc以及orm框架設計兼容。在jdbcTemplate,IbatiTemplate每執行一次sql操作,就需要獲取conn,執行sql,關閉conn。如果不存在事務上下文,這樣做沒有任何問題,獲取一次連接,使用完成,然后就是比。但是如果存在事務上下文,每次獲取的conn并不一定是真實的物理連接,所以關閉的時候,也不能直接關閉這數據庫連接。Spring的中定義一個ConnectionHandle對象,這個對象持有一個數據庫連接對象,以及該連接上的引用次數(retain屬性)。每次復用一次就retain++ 操作,沒關閉一次,就執行retain-- 操作,在retain 為0的時候,說明沒有任何連接,就可以進行真實的關閉了。

      主站蜘蛛池模板: 亚洲欧美一区二区成人片| 欧美疯狂xxxxbbbb喷潮| 久久久精品2019中文字幕之3| 国产精品人妻一区二区高 | 一本大道无码av天堂| 亚洲一线二线三线品牌精华液久久久| 久久亚洲人成网站| 亚洲一区三区三区成人久| 汾阳市| 亚洲国产精品毛片在线看| 人妻系列中文字幕精品| 国产线播放免费人成视频播放| 国产av丝袜熟女一二三| 国产二区三区不卡免费| 三级国产在线观看| 国产精品久久久久久妇女| 在线看高清中文字幕一区| 亚洲欧洲一区二区精品| 国产香蕉尹人综合在线观看| 日韩乱码人妻无码系列中文字幕| 欧美视频精品免费覌看| 亚洲午夜久久久影院伊人| 精品无码一区二区三区在线| 天天躁日日躁狠狠躁2018| 免费AV片在线观看网址| 亚洲欧美偷拍另类A∨| 黑人强伦姧人妻久久| 成人看的污污超级黄网站免费| 又爽又黄又无遮挡的激情视频| 鄂托克旗| 777奇米四色成人影视色区| 自偷自拍亚洲综合精品| 无码精品人妻一区二区三区中| 极品人妻少妇一区二区三区| 特级毛片在线大全免费播放| 欧美成人精品手机在线| 麻豆国产成人AV在线播放| 西西人体www大胆高清| 国产美女69视频免费观看| 大地资源中文第三页| 亚洲精品麻豆一二三区|