mybatis(4) - TDDL下的getConnection是如何處理的

首先咱們來看看DataSourceUtils.doGetConnection的源碼:spring-jdbc jar下的org.springframework.jdbc.datasource提供用來獲取數據庫鏈接java

經過前幾篇幅對mybatis的執行過程分析可知: 
在新建defaultSqlSession實例時,其內部成員對象SpringManagedTransaction實例內擁有的connect對象仍是null,但最終在執行SimpleExecutor.prepareStatement方法內獲取真實鏈接時會跳入DataSourceUtils.doGetConnection
spring

那關鍵來了,這個getConnection()作了什麼呢?sql

結論

  1. TDataSource 與 mycat的實現不一樣:
    前者是在應用程序內經過分庫分表策略(TableRule) dispatcher到具體的單個庫(TGroupDataSource)具體單個表,經過TDruidDataSource (實際上內部仍是DruidDataSource) 來具體處理; 而mycat是代理了數據庫層,應用無感知,經過mycat配置table的dataNode與rule來肯定分庫分表規則。
  2. 在spring中的使用方式 DruidDataSource 與 TDataSource  基本相同。不一樣的是: 在常規的執行SimpleExecutor.prepareStatement方法準備prepareStatement前獲取Connection時:
    1. 數據源 DruidDataSource:此刻是直接開啓Druid鏈接;
    2. 數據源 TDataSource :  此時並不會直接開啓!!而是在以後的PreparedStatementHandler調用PreparedStatement真正執行時, 將經過分庫分表策略定位到具體的DruidDataSource,再開啓Druid鏈接

DruidDataSource

在執行getConnection方法會真正的初始化,並從DruidPooledConnection數據庫鏈接池管理中獲取鏈接。(詳見getConnectionDirect方法)數據庫

TDataSource

  1. 每個分表配置對應一個TableRule;每一個庫真實對應一個DruidDataSource, 多個DruidDataSource能夠對應相同的一個 TGroupDataSource 。(當前只使用了分表分庫功能,只有一個庫對應一個group)
  2. 啓動時會從遠端配置服務上拉取分庫分表配置,構建 VirtualTableRoot :記錄每個分表配置 TableRule  ( extends VirtualTable  )
    2019-02-28 16:45:50,796 [main] WARN  [com.taobao.tddl.interact.rule.VirtualTableRoot] [VirtualTableRoot.java:40] [trace=,span=,parent=,name=,app=,begintime=,endtime=] - virtual table start to init :decision_apply_data
    2019-02-28 16:45:50,995 [main] WARN  [com.taobao.tddl.interact.rule.VirtualTableRoot] [VirtualTableRoot.java:50] [trace=,span=,parent=,name=,app=,begintime=,endtime=] - virtual table inited :decision_apply_data
    2019-02-28 16:45:50,995 [main] WARN  [com.taobao.tddl.interact.rule.VirtualTableRoot] [VirtualTableRoot.java:40] [trace=,span=,parent=,name=,app=,begintime=,endtime=] - virtual table start to init :decision_exec_data_req
    2019-02-28 16:45:51,175 [main] WARN  [com.taobao.tddl.interact.rule.VirtualTableRoot] [VirtualTableRoot.java:50] [trace=,span=,parent=,name=,app=,begintime=,endtime=] - virtual table inited :decision_exec_data_req
    TableRule中有:(VirtualTableRoot.init)
    1. 每一個真實的庫Group與每一個具體表的對應關係;
    2. 分表規則、分庫規則。
    3. 庫名、表名的格式

執行過程

本文直接從【執行SimpleExecutor.prepareStatement方法】開始講述,前面的過程與常規過程相似。bootstrap

(TDataSource  -> TConnectionImp -> TPreparedStatementImp )-> 分庫(TGroupDataSource -> TGroupConnection -> TGroupPreparedStatement -> 實際 (OneDBSelector ->DataSourceWrapper ->TDruidDataSource -> DruidDataSource -> DruidPooledConnection)mybatis

具體的執行過程以下:app

  • SimpleExecutor.prepareStatement方法構建的prepareStatement是由具體的Connection對象肯定的:TDataSource.getConnection方法返回Connection是TConnectionImp; 其構建的prepareStatement是TPreparedStatementImp
  • 以後常規執行PreparedStatementHandler內具體方法(execute等)時,真實是使用TPreparedStatementImp 其內部會肯定具體的TGroupDataSource與真實的分表名(原sql被改成真實執行sql)
  • 再經過TGroupDataSource獲取的鏈接TGroupConnection 構建TGroupPreparedStatement
  • 進入TGroupPreparedStatement的具體方法(execute等)後 :TGroupConnection.createNewConnection方法會真正調用TDruidDataSource.getConnection來真正獲取到DruidDataSource進行真實數據庫鏈接獲取。

getConnection

對getConnection的處理只是初始化了對象。通常默認使用TConnectionImpui

很重要的是:會將全部的分庫組TGroupDataSource 綁定在這個TConnectionImp上!
spa

TDDL何時真正開啓鏈接

 最終執行的步驟是在:SimpleExecutor調用PreparedStatementHandler調用具體執行方法(execute等)來dml。在這以前會經過prepareStatement方法來使用指定的connection封裝PreparedStatementHandler對象。
TConnectionImp的prepareStatement方法構建的是TPreparedStatementImp對象。.net

接着咱們來看看是若是處理分庫分表的:

  1. 首先咱們看PreparedStatementHandler再執行時的入參中的sql,發現此時仍是沒有肯定分表的
  2. 關鍵點
    執行到TPreparedStatementImp (TStatementImp)的executeQuery時,會調用 buildSqlExecutionContextUsePipeline 肯定好具體要調用哪一個庫的哪一個表等信息保存在RealSqlContextImp( SpringBasedDispatcherImpl implements SqlDispatcher)

    PipelineBootstrap的bootstrap根據配置文件中的originalSql來斷定是否走SimpleHintParser(有一些特殊的操做能夠用到。eg. tddl 支持批量插入的方法

    com.taobao.tddl.client.jdbc.executeplan.ExecutionPlanImp中的內容包含肯定好的真實的執行sql及真實的庫group等信息
  3. 經過肯定好的分組庫配置獲取鏈接TGroupConnection,並構建TGroupPreparedStatement。

    此時的dbSelectorId爲真實Group標識

  4. TGroupPreparedStatement.executeQuery:  

    着重看下這個方法的「gotoRead」標記。 根據originalSql的類型會斷定在TGroupConnectiongetBaseConnection方法中是找讀庫仍是寫庫
  5. AbstractDBSelector.tryExecute: 會根據策略選中指定group下的惟一的dataSource。
  6. 經過TGroupConnection.createNewConnection最終調用DruidDataSource.getConnection!!
相關文章
相關標籤/搜索