Mybatis整合Spring實現事務管理的源碼分析
一:前言
沒有完整看完,但是看到了一些關鍵的地方,這裏做個記錄,過程會有點亂,以後逐漸補充最終歸檔為完整流程;相信看過框架源碼的都知道過程中無法完全確定是怎樣的流程,畢竟不可能全部都去測試一遍
,但是看的過程中靈感的顯現很重要(就是直覺知道接下來的步驟是什麽應該是什麽之類的,但是這個自覺是猜的而非蒙的,即過程裏是有往會遞推看到了一些關鍵點的而不是拋色子來確定是哪個子類)
,因此自己寫的時候也無法將看的過程裏產生的想法寫得很細,過程也有點跳,如果大家有疑問最好自己去驗證(方式就是搜索然後看哪裏調用了這樣一步步看下去就行,有些小技巧就是如果是public那麽一般都是由外部類調用[入口],如果是protected卻沒實現
說明在之類裏有實現,如果已經實現說明此方法在父類裏會被調用,如果是private那麽肯定在當前類會被調用);
二:重要類或方法
1)對於Mybatis
1.org.apache.ibatis.executor.Executor接口,有大概BatchExecutor/ReuseExecutor/SimpleExecutor三個子類有共同的父類BaseExecutor,它是DefaultSqlSession類的組件,sqlSession對象的如selectOne實際上是由executor執行的;
2.org.apache.ibatis.transaction.Transaction接口,它的實現類有多個,但是每個實現類裏都有DataSource屬性用於產生數據源和數據庫服務交互;
3.SpringManagedTransaction是支持Spring管理Mybatis事務的關鍵;
4.DefaultSqlSessionFactory
5.DefaultSqlSession
它們之間的重要關系:sqlsession裏有executor;executor裏有transaction對象;transaction裏有datasource;
流程:sqlsession執行代碼委托為executor執行,executor裏通過transaction獲得connection;而transaction又通過判斷threadlocalmap裏是否有ConnectionHolder對象;如果沒有則通過datasource獲得一個,否則返回存在threadlocalmap裏的;
三:執行流程
如:sqlSession.selectOne執行流程:
3.1selectOne最終轉到selectList;
3.2調用sqlsession的屬性executor.query方法執行;
3.3在BaseExecutor的query方法裏執行這一句:list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);,因此這一句代碼很關鍵;
3.4接著看裏面有this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);方法;
3.5接著看SimpleExecutor的doQuery方法(看源碼很多時候是靠即時的靈感,比較難完整描述看時的思路和過程);
補充開始:1.接著看stmt = this.prepareStatement(handler, ms.getStatementLog());,很重要,因為statement執行sql語句也是通過它內部的connection對象來執行的;
2.看Connection connection = this.getConnection(statementLog);,接著看裏面有:Connection connection = this.transaction.getConnection(); 重要重要,transaction終於在執行sql的過程裏出現了;
3.整合Spring的情況下通過本文的上下文知道此transaction是SpringManagedTransaction對象;
4.接著看SpringManagedTransaction的this.openConnection();有代碼:
this.connection = DataSourceUtils.getConnection(this.dataSource); this.autoCommit = this.connection.getAutoCommit(); this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
5.我們看DataSourceUtils.getConnection(this.dataSource);,然後轉到doGetConnection方法裏有代碼:
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource); if(conHolder == null ...) {通過dataSource獲得一個新的connection} else{ conHolder.getConnection(); //return一個在threadlocalmap裏的connection對象; }
註意,上上面的DataSourceUtils和這裏當TransactionSynchronizationManager及ConnectionHolder是spring裏的類不是mybatis的,裏面的threadlocal對象都是靜態的,因此mybatis可以獲得spring中放在threadlocalmap的connectionholder對象;
而spring是否產生connectionholder以及是否放到threadlocalmap裏是根據txAdvice策略來的;
補充結束;
3.6接著看handler.query(stmt, resultHandler);然後可以挑RoutingStatementHandler的這個方法看;
3.7會委托給其它handler處理,這裏可暫定為PreparedStatementHandler類;
3.8看到ps.execute();,後面沒什麽好看了就是jdk中通過stmt執行sql的方式,這裏關鍵的是stmt裏的connection是什麽;
四:和Spring整合過程中重要步驟
1.配置了org.mybatis.spring.SqlSessionFactoryBean,默認情況下它內部的transactionFactory屬性是SpringManagedTransactionFactory對象(如果不想Spring來管理事務則可以主動指定sqlSessionFactoryBean的transactionFactory為別的類);
2.SqlSessionFactoryBean的sqlSessionFactory的configuration的environment裏保存了transactionFactory對象為SpringManagedTransactionFactory對象,這一步很重要;
3.我們來看DefaultSqlSessionFactory的openSessionFromDataSource方法(真正獲得sqlSession對象的地方),裏面有代碼
Environment environment = this.configuration.getEnvironment(); TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); Executor executor = this.configuration.newExecutor(tx, execType); var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
註意:execType默認對應的是SimpleExecutor,且這個executor裏保存了SpringManagedTransactionFactory產生的SpringManagedTransaction對象,這裏先明確一下;
4.上面已經明確了sqlSession執行語句是委托為exector來執行的;後面的步驟和三裏的一致了就不贅述了;
五:Spring裏事務管理的重要類和方法
1.org.springframework.transaction.interceptor.TransactionInterceptor,極其重要,這個是當執行pointcut方法時將會由這個事務攔截器根據<tx:attributes>配置的propagation做一些額外處理(是一個around),包括是否需要產生connection對象和將這個connection對象的autoCommit設置為什麽值(SpringManagedTransaction的this.openConnection();會用到此值),比如REQUIRED就會先判斷threadlocalmap裏是否有connectionholder,有不做預處理沒有則通過datasource獲取connection並設置為autoCommit為false,然後通過
connectionholer包裝此connection並set到threalocalmap裏;
2.org.springframework.jdbc.datasource.DataSourceTransactionManager,極其重要,是spring用來根據propagation策略來執行不同的邏輯的重要組件(在TransactionInterceptor的invoke方法裏執行);
3.TxNamespaceHandler用來處理名稱空間為tx的元素;
4.TxAdviceBeanDefinitionParser用來解析<tx:advice元素,通過doParse處理;
5.NameMatchTransactionAttributeSource,極其重要,存儲了<tx:attributes裏配置的策略供TransactionInterceptor使用;
補充:如果要看懂spring的事務管理,可以從TransactionInterceptor的invoke方法實現開始看,這個是入口函數,而內部用到的ConnectionHolder則是和Mybatis有交互的類;
Mybatis整合Spring實現事務管理的源碼分析