您的位置:首页 > 其它

sharding-jdbc-how2work 当当的sharding-jdbc剖析

2016-02-12 23:36 190 查看

> 空开 否则右边挡了,好不优雅的办法

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>

>







JDBC出发点

整体思路:实现JDBC规范的接口 分析com.dangdang.ddframe.rdb.sharding.jdbc包 实现javax.sql.DataSource接口 ShardingDataSource 实现java.sql.Connection接口 ShardingConnection 实现java.sql.Statement ShardingStatement 实现java.sql.PreparedStatement ShardingPreparedStatement 实现java.sql.ResultSet AbstractShardingResultSet 重新实现的方式 AbstractUnsupportedOperationXXXX描述不支持的接口实现 通过这一系列的类可以看出不支持哪些操作 AbstractXXXXAdapter 这一层意义? WrapperAdapter 具体实现分析 ShardingDataSource 根据ShardingRule实例准备DatabaseMetaData实例 用于构建ShardingConnection实例 准备DatabaseMetaData实例的过程: 根据原有Datasource获取到数据库产品的信息 一次准备的所有数据源必须是同一种数据库产品 不能既有MySql又有DB2 ShardingConnection 主要完成createStatement、prepareStatement接口的实现 实现createStatement、prepareStatement接口 主要过程是创建ShardingStatement、ShardingPreparedStatement实例 创建上述两实例需要SQLRouteEngine实例 SQLRouteEngine实例实在connection构造的时候完成创建 需要ShardingRule、DatabaseType SQLRouteEngine干什么用的呢?用于分库分表的规则逻辑的接入点 ShardingStatement 实现java.sql.Statement接口 不支持的操作参见AbstractUnsupportedOperationStatement currentResultSet = ResultSetFactory.getResultSet(generateExecutor(sql).executeQuery(), mergeContext); ShardingPreparedStatement AbstractShardingResultSet

Executor

根据SQLRouteEngine与sql 组装出StatementExecutor route出SQLRouteResult SQLRouteResult拿到执行单元SQLExecutionUnit 执行单元包装了sql及其相应的dataSource的key名 拿到MergeContext StatementExecutor本质在于包装了多个Statement及相应sql 在代码中用StatementEntity做了表示 这里的sql已经是用物理表名置换了逻辑表名后的sql 这里的Statement已经是相应jdbc driver对应的原生的Statement

SQLRouteEngine

1. route是其核心的对外暴露的接口 parseSQL接口用SQLParseEngine parse出SQLParsedResult 根据parse出的SQLParsedResult结果实例中的 ConditionContext、逻辑表名、SQLBuilder实例 与shardingRule(SQLRouteEngine的实例变量) 加工出SQLExecutionUnit实例列表 1.1 parseSQL 1. SQLParserFactory根据逻辑sql(还没有实际的物理表名的sql)、分片列名、数据库类型、查询的条件参数创建SQLParseEngine 1.1 创建SQLParseEngine主要过程有: a. 用阿里的druid解析出语法树com.alibaba.druid.sql.ast.SQLStatement b. 根据sql语句是增删改查来决定用哪种visitor实例(用于后置处理) 1.2 parse过程 依赖visitor 含有or条件的特殊处理 具体的visitor TODO or条件的特殊处理 1.2 route 需要的要素:shardingRule(SQLRouteEngine的实例变量), ConditionContext,逻辑表名,SQLBuilder实例 又分三种: SingleTableRouter--route-->SingleRoutingResult //单表(逻辑表)操作 BindingTablesRouter--route-->BindingRoutingResult MixedTablesRouter--route-->RoutingResult(CartesianTablesRouter) SingleTableRouter routeDataSources ShardingValue DatabaseShardingStrategy.doSharding routeTables ShardingValue TableShardingStrategy.doSharding BindingTablesRouter BindingRoutingResult.bind BindingRoutingDataSource.bind BindingRoutingTableFactor

visitor

五种。 看懂visitor前提是要了解 编译器常用的访问者这种设计模式 com.dangdang.ddframe.rdb.sharding.parser.visitor.basic.mysql MySQLInsertVisitor MySQLDeleteVisitor MySQLSelectVisitor MySQLUpdateVisitor OrVisitor visitor通过ParseContex 做了mergeCurrentConditionContext、getParsedResult、 visitor还getSQLBuilder AbstractMySQLVisitor 增删改查都用到的 重新实现visit以下类型AST节点的逻辑: SQLVariantRefExpr,SQLExprTableSource,SQLPropertyExpr, SQLBinaryOpExpr,SQLInListExpr,SQLBetweenExpr SQLVariantRefExpr sql中的问号占位符,:xxx这种命名参数, @max_order_id:= 这种 select @max_order_id:=max(order_id) from order where id=? and user_id=:userId 父类不仅用@@ 替换?, 同时用实际参数值替换了?占位符 sharding-jdbc将占位符换成真正参数值的 动作交由ShardingPreparedStatement完成 SQLExprTableSource select * from order o where o.id=1 from后面的order就是SQLExprTableSource select * from (select * from order o where o.id=1) order_alias from后面的order是SQLExprTableSource,但order_alias不是 order_alias 是SQLSubqueryTableSource SQLSubqueryTableSource与SQLExprTableSource 都是SQLTableSourceImpl的子类 插入parseContext.addTable(x)逻辑: 1. 处理表名及其别名中特殊字符--> []`'\ 2. 将表名及其别名加入RouteContext SQLPropertyExpr select o.name from order o where o.id=1 此处的name和id都是SQLPropertyExpr 接在表别名点号后面的是SQLPropertyExpr 针对"select * from T_ORDER where T_ORDER.order_id=1002 这种sql重新实现此类型节点的visitor 过程:将T_ORDER.order_id换成别名t_order.order_id 其余的SQLPropertyExpr沿用父类逻辑 SQLBinaryOpExpr select * from order o where o.id=1 左值o.id 右值 1 就是描述运算的 select 1+1 1+1也是 1. 发现有or操作时, 要将parseContext中存在or条件标志置成true 便于后面特殊处理 2. 发现有=(等于比较)操作时将其加入到 parseContext的ConditionContext中 SQLInListExpr select * from user u where u.id in (1,3,4,5) targetList是in后面的列表 expr是in前面的表达式 in操作与上面=操作的处理相同 SQLBetweenExpr select * from t_order_0 where order_id between 1004 and 1008 between与上面=操作相同 MySQLSelectVisitor 重新实现/更新visit以下类型AST节点的逻辑: MySqlSelectQueryBlock,SQLSelectItem,SQLAggregateExpr SQLOrderBy,MySqlSelectGroupByExpr, MySqlSelectQueryBlock.Limit, endVisit(final SQLSelectStatement x) MySqlSelectQueryBlock 插入逻辑: 告诉程序当前在处理哪个表的子查询 SQLSelectItem 插入逻辑: 更新itemIndex给处理SQLAggregateExpr时使用 SQLAggregateExpr 聚合: String[] AGGREGATE_FUNCTIONS = { "AVG", "COUNT", "MAX", "MIN", "STDDEV", "SUM" } 对分库分表时的聚合插入逻辑处理 主要是分析出是哪种聚合 聚合的哪一列 然后扔进ParseContext的MergeContext 使用逻辑表名查询时,聚合计算是不分片的 使用物理表名查询时, 聚合计算是报错的,sharding不认识物理表名 SQLOrderBy 类似SQLAggregateExpr的处理 对分库分表时的order by插入逻辑处理 主要是分析出是哪种排序形式 是哪一列(支持多列) 然后扔进ParseContext的MergeContext MySqlSelectGroupByExpr 类似SQLAggregateExpr、SQLOrderBy的处理 MySqlSelectQueryBlock.Limit 处理ParseContext的MergeContext的部分 类似SQLAggregateExpr、SQLOrderBy的处理 context中的offset与rowcount是原有sql中真是的值 多一个逻辑: 到实际物理表查询的sql在此处被改写了, offset从0开始,rowcount是原有sql里的offset加上原有sql里的rowcount 当然同时支持(兼容)?占位符的情况 日志更直观: Logic SQL: select * from t_order o order by o.order_id limit 1,2 route sql to db: [db0] sql: [SELECT * FROM t_order_0 o ORDER BY o.order_id LIMIT 0, 3] route sql to db: [db0] sql: [SELECT * FROM t_order_1 o ORDER BY o.order_id LIMIT 0, 3] endVisit(final SQLSelectStatement x) 当一个查询结束后 从MergeContext拿到AggregationColumns 进行加工,举例,主要逻辑如下: select avg(order_id) from t_order 加工成 SELECT AVG(order_id)[Token(, COUNT(order_id) AS sharding_gen_1, SUM(order_id) AS sharding_gen_2)] FROM [Token(t_order)] 主要是补了sum和count MySQLDeleteVisitor 更新MySqlDeleteStatement处理逻辑 将当前表名及其别名加入RouteContext 感觉跟AbstractMySQLVisitor里对SQLExprTableSource 处理逻辑有重复部分 MySQLInsertVisitor 将当前表名及其别名加入RouteContext 同delete 插入的列也需要纳入ParseContext的ConditionContext管理 以保证插入到正确的表中! MySQLUpdateVisitor 将当前表名及其别名加入RouteContext 同delete 没有其他处理逻辑了 那么分片键再次更新就不能正确的落到相应的物理表中了 分片键值更新 分片键还作为update的where条件 update t_order_0 set order_id=1011 where order_id=1002
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: