[首页]
[文章]
[教程]
首页
Web开发
Windows开发
编程语言
数据库技术
移动平台
系统服务
微信
设计
布布扣
其他
数据分析
首页
>
数据库技术
> 详细
sharding-jdbc-how2work 当当的sharding-jdbc剖析
时间:
2016-02-13 00:25:15
阅读:
487
评论:
0
收藏:
0
[点我收藏+]
> 空开 否则右边挡了,好不优雅的办法
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
sharding-jdbc-how2work 当当的sharding-jdbc剖析
原文:http://www.cnblogs.com/simoncook/p/5187357.html
踩
(
0
)
赞
(
0
)
举报
评论
一句话评论(
0
)
登录后才能评论!
分享档案
更多>
2021年09月23日 (328)
2021年09月24日 (313)
2021年09月17日 (191)
2021年09月15日 (369)
2021年09月16日 (411)
2021年09月13日 (439)
2021年09月11日 (398)
2021年09月12日 (393)
2021年09月10日 (160)
2021年09月08日 (222)
最新文章
更多>
2021/09/28 scripts
2022-05-27
vue自定义全局指令v-emoji限制input输入表情和特殊字符
2022-05-27
9.26学习总结
2022-05-27
vim操作
2022-05-27
深入理解计算机基础 第三章
2022-05-27
C++ string 作为形参与引用传递(转)
2022-05-27
python 加解密
2022-05-27
JavaScript-对象数组里根据id获取name,对象可能有children属性
2022-05-27
SQL语句——保持现有内容在后面增加内容
2022-05-27
virsh命令文档
2022-05-27
教程昨日排行
更多>
1.
list.reverse()
2.
Django Admin 管理工具
3.
AppML 案例模型
4.
HTML 标签列表(功能排序)
5.
HTML 颜色名
6.
HTML 语言代码
7.
jQuery 事件
8.
jEasyUI 创建分割按钮
9.
jEasyUI 创建复杂布局
10.
jEasyUI 创建简单窗口
友情链接
汇智网
PHP教程
插件网
关于我们
-
联系我们
-
留言反馈
- 联系我们:wmxa8@hotmail.com
© 2014
bubuko.com
版权所有
打开技术之扣,分享程序人生!