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

首先我们来看看DataSourceUtils.doGetConnection的源码:spring-jdbc jar下的org.springframework.jdbc.datasource提供用来获取数据库连接

通过前几篇幅对mybatis的执行过程分析可知: 
在新建defaultSqlSession实例时,其内部成员对象SpringManagedTransaction实例内拥有的connect对象还是null,但最终在执行SimpleExecutor.prepareStatement方法内获取真实连接时会跳入DataSourceUtils.doGetConnection
4394cb5149eeae71a9552756edcbe2587de.jpg

那关键来了,这个getConnection()做了什么呢?

结论

  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方法)

738ffd2b100e3a2ea45830287545350d62d.jpg

122f8e73aa26aa6e0cb573d6180c32b7f95.jpg

TDataSource

  1. 每一个分表配置对应一个TableRule;每个库真实对应一个DruidDataSource, 多个DruidDataSource可以对应相同的一个 TGroupDataSource 。(当前只使用了分表分库功能,只有一个库对应一个group)
    62a83edab4b062360318425195d8cb15f4b.jpg
  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. 库名、表名的格式
      a053471a9a943f0d26edc26384d71ca5bcd.jpg

执行过程

本文直接从【执行SimpleExecutor.prepareStatement方法】开始讲述,前面的过程与常规过程类似。

(TDataSource  -> TConnectionImp -> TPreparedStatementImp )-> 分库(TGroupDataSource -> TGroupConnection -> TGroupPreparedStatement -> 实际 (OneDBSelector ->DataSourceWrapper ->TDruidDataSource -> DruidDataSource -> DruidPooledConnection)

具体的执行过程如下:

  • 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进行真实数据库连接获取。

48409353ba5fcb7b2f1a922e96d9496b1e8.jpg

getConnection

对getConnection的处理只是初始化了对象。一般默认使用TConnectionImp

ff6f0c86cbabe52b105082b8f1b811bf5f8.jpg

很重要的是:会将所有的分库组TGroupDataSource 绑定在这个TConnectionImp上!
bb7fa906e900cf994f85bd6f3e459eafe74.jpg

TDDL什么时候真正开启连接

 最终执行的步骤是在:SimpleExecutor调用PreparedStatementHandler调用具体执行方法(execute等)来dml。在这之前会通过prepareStatement方法来使用指定的connection封装PreparedStatementHandler对象。
TConnectionImp的prepareStatement方法构建的是TPreparedStatementImp对象。

接着我们来看看是如果处理分库分表的:

  1. 首先我们看PreparedStatementHandler再执行时的入参中的sql,发现此时还是没有确定分表的
    f9528ac408c1090ac92edf64663c2da9571.jpg
  2. 关键点
    执行到TPreparedStatementImp (TStatementImp)的executeQuery时,会调用 buildSqlExecutionContextUsePipeline 确定好具体要调用哪个库的哪个表等信息保存在RealSqlContextImp( SpringBasedDispatcherImpl implements SqlDispatcher)
    73437f5106b855d9c4883eca1dbb7ed0dc3.jpg
    PipelineBootstrap的bootstrap根据配置文件中的originalSql来判定是否走SimpleHintParser(有一些特殊的操作可以用到。eg. tddl 支持批量插入的方法
    c780a1fc9fad9eecaf7657951e84327c9bc.jpg
    com.taobao.tddl.client.jdbc.executeplan.ExecutionPlanImp中的内容包含确定好的真实的执行sql及真实的库group等信息
    7fa045b08deceaeeed3571ce190c81d32c2.jpg
  3. 通过确定好的分组库配置获取连接TGroupConnection,并构建TGroupPreparedStatement。
    2a7183bee852563021a45a67853bfdb52ce.jpg
    此时的dbSelectorId为真实Group标识
    b753361600ccf73d8d5c12d22bd793df441.jpg
    2540f7c9669e5e18d12df14f1cdaa4f78c1.jpg
  4. TGroupPreparedStatement.executeQuery:  
    cd054e45e553af3f2fe885228653e8a05d4.jpg
    着重看下这个方法的“gotoRead”标记。 根据originalSql的类型会判定在TGroupConnectiongetBaseConnection方法中是找读库还是写库
    95a3ae265d514b3f00302f248606bd7e483.jpg
  5. AbstractDBSelector.tryExecute: 会根据策略选中指定group下的唯一的dataSource。
    9659b08c5e5b878307ac7063bfc69253fe3.jpg
  6. 通过TGroupConnection.createNewConnection最终调用DruidDataSource.getConnection!!
    06eb9a1a8afe8d6004099ad77ef0341db21.jpg

转载于:https://my.oschina.net/u/3434392/blog/3016263

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值