oceanus-58总体框架理解
1.总体思路:
通过约定的XML规则(分表分库规则)和 封装jdbc的Connection和PreparedStatement来实现SQL解析,sql路由和sql重写。
2. 3个核心类:ConnectionWrapper(JDBC Connection包装),PreparedStatementWrapper( JDBC PreparedStatement包装),SimpleExecutor(sql执行器,类似mybatis的SimpleExecutor)
3. 3个上下文传参数:ConnectionContext,StatementContext,transactionContext。
4. 真正干活的类:
(1)DefaultStatementContextBuilder类:解析SQL并保存BatchItem到StatementContext,--作者貌似直接用的mycat里面的sql解析的代码,直接拿来主义实现价值啊。
public StatementContext build(String sql, StatementContext context) throws SQLException { if (context == null) { context = new StatementContext(); StatementContext.setContext(context); if (logger.isDebugEnabled()) { logger.debug("create context!sql=" + sql); } } if (context.getCurrentBatch().getSql() == null) { context.getCurrentBatch().setSql(sql); }
StatementContextHandler handler = null; if (context.isBatch()) { handler = HandlerFactory.create(StatementType.BATCH); StatementContext resultContext = handler.handle(sql, context); processPreparedValues(resultContext); return resultContext; }
TrackerExecutor.trackBegin(TrackPoint.PARSE_SQL, sql); SQLParser parser = StatementHelper.createSQLParser(); try { DMLStatementNode statementNode = (DMLStatementNode) parser .parseStatement(sql); switch (statementNode.getNodeType()) { case NodeTypes.CURSOR_NODE: handler = HandlerFactory.create(StatementType.SELECT); break; case NodeTypes.DELETE_NODE: handler = HandlerFactory.create(StatementType.DELETE); break; case NodeTypes.UPDATE_NODE: handler = HandlerFactory.create(StatementType.UPDATE); break; case NodeTypes.INSERT_NODE: handler = HandlerFactory.create(StatementType.INSERT); break; case NodeTypes.CALL_STATEMENT_NODE: handler = HandlerFactory.create(StatementType.CALLABLE); break; }
StatementContext resultContext = handler.handle(statementNode, context);
TrackerExecutor.trackEnd(TrackPoint.PARSE_SQL);
processPreparedValues(resultContext); return resultContext;
} catch (StandardException se) { System.out.println("sql parse error, sql:"+sql); se.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } processPreparedValues(context); return context; }
(2)DefaultTargetDispatcher:根据batchItem和batchItem中的tableInfo获取路由信息和重写SQL,达到路由到指定的分库分表的目的
Set<RouteTarget> getSpecifyTargets(TableInfo tableInfo, BatchItem batchItem) { Set<RouteTarget> targetSet = new LinkedHashSet<RouteTarget>(); Configurations configurations = Configurations.getInstance();
/** * 解析where中符合分库分表字段的值 */ Map<String, List<TableColumn>> resolveColumns = RouteHelper .getResolveColumns(tableInfo.getOrgName(), batchItem.getAnalyzeResult()); List<Map<String, Object>> parameters = RouteHelper .getParameterValues(resolveColumns); Set<Integer> indexs = new HashSet<Integer>(); TableDescription desc = configurations.getTableDescription(tableInfo .getOrgName()); List<NameNodeHolder> nameNodes = desc.getNameNodes(); Function func = desc.getFunction();//分库分表函数,本质就是获取table节点中namenode节点的序号 for (Map<String, Object> item : parameters) { checkParameters(item, batchItem); int i = func.execute(nameNodes.size(), item); indexs.add(i); }
if (indexs.size() > 0) { AnalyzeResult analyzeResult = batchItem.getAnalyzeResult(); HavingInfo havingInfo = analyzeResult.getHavingInfo(); if (havingInfo != null) { AnalyzerCallback callback = havingInfo.getCallback(); if (callback != null) { callback.call(); } } } if ((!batchItem.getAnalyzeResult().getAppendResultColumns().isEmpty() || batchItem .getAnalyzeResult().getLimit() != null) && indexs.size() > 1) {// 存在limit或者avg等聚集函数,需要重新生成sql Collection<AnalyzerCallback> analyzerCallbacks = batchItem .getAnalyzeResult().getAnalyzerCallbacks(); if (batchItem.getAnalyzeResult().getLimit() != null) { SqlValueItem limitItem = batchItem.getAnalyzeResult() .getLimit(); SqlValueItem offsetItem = batchItem.getAnalyzeResult() .getOffset(); if(offsetItem==null){ offsetItem=new SqlValueItem(); offsetItem.setValue(0); } if (limitItem.getParameterIndex() > 0 && offsetItem.getParameterIndex() > 0) {// limit ?,? Integer limitSize = limitItem.getValue() + offsetItem.getValue(); batchItem.getCallback(limitItem.getParameterIndex()) .setParameter(limitSize); batchItem.getCallback(offsetItem.getParameterIndex()) .setParameter(0);
if(limitItem.getParameterIndex() > offsetItem.getParameterIndex()){ batchItem.getCallback(offsetItem.getParameterIndex()) .setParameterIndex(limitItem.getParameterIndex());
batchItem.getCallback(limitItem.getParameterIndex()) .setParameterIndex(offsetItem.getParameterIndex()); } } else if (limitItem.getParameterIndex() > 0) {// limit 1,? Integer limitSize = limitItem.getValue() + offsetItem.getValue(); batchItem.getCallback(limitItem.getParameterIndex()) .setParameter(limitSize); } else if (offsetItem.getParameterIndex() > 0) {// limit ?,10 batchItem.getCallback(offsetItem.getParameterIndex()) .setParameter(0); } } for (AnalyzerCallback callback : analyzerCallbacks) { callback.call(); } } else {// 在单库路由的情况下,如果检测到是limit ?,?,就置换Parameter顺序 SqlValueItem limitItem = batchItem.getAnalyzeResult() .getLimit(); SqlValueItem offsetItem = batchItem.getAnalyzeResult() .getOffset();
if(limitItem !=null && offsetItem !=null && limitItem.getParameterIndex() > offsetItem.getParameterIndex()){
batchItem.getCallback(offsetItem.getParameterIndex()) .setParameterIndex(limitItem.getParameterIndex());
batchItem.getCallback(limitItem.getParameterIndex()) .setParameterIndex(offsetItem.getParameterIndex()); } } for (Integer i : indexs) {// 生成target NameNode nameNode = configurations.getNameNode( tableInfo.getOrgName(), i); DefaultRouteTarget target = this.createTarget(batchItem, nameNode, tableInfo); targetSet.add(target); }
for (RouteTarget item : targetSet) { DefaultRouteTarget target = (DefaultRouteTarget) item; SqlExecuteInfo info = new SqlExecuteInfo(); info.setCallbacks(new LinkedHashSet<ParameterCallback<?>>(batchItem .getCallbacks()));
if (desc.isDifferentName()) { info.setExecuteSql(configurations.getGenerator().generate( (NameNodeHolder) target.getNameNode(), batchItem.getAnalyzeResult())); } else if ((!batchItem.getAnalyzeResult().getAppendResultColumns().isEmpty() || batchItem .getAnalyzeResult().getLimit() != null) && nameNodes.size() > 1) {// 存在limit或者avg等聚集函数,需要重新生成sql,必须要超过1个路由结果 info.setExecuteSql(configurations.getLimitAvgGenerator() .generate((NameNodeHolder) target.getNameNode(), batchItem.getAnalyzeResult())); } else { info.setExecuteSql(batchItem.getSql()); } target.setExecuteInfo(info); } return targetSet; }
(3)SimpleExecutor 和 HandlerFactory:
根据StatementContext的RouteTarget(路由数据),
新建事务并获取数据库连接, 实际执行JDBC curd操作的类.
兴趣点:发现doUpdate的时候有用同步工具类:
CyclicBarrier barrier = new CyclicBarrier(n);
@SuppressWarnings({ "rawtypes", "unchecked" })public class SimpleExecutor implements Executor { static Logger logger = LoggerFactory.getLogger(SimpleExecutor.class); static final ExecuteHandler<Integer> deleteHandler = new DeleteExecuteHandler(); static final ExecuteHandler<Integer> insertHandler = new InsertExecuteHandler(); static final ExecuteHandler<Integer> updateHandler = new UpdateExecuteHandler(); static final ExecuteHandler<ResultSet> queryHandler = new QueryExecuteHandler();
@Override public Object execute(StatementContext context, ExecuteCallback callback) throws SQLException {
switch (context.getCurrentBatch().getAnalyzeResult().getStatementType()) { case SELECT: return this.doQuery(context, callback); case INSERT: case UPDATE: case DELETE: return doUpdate(context, callback); default: break; } return null; }
ExecuteHandler<?> getHandler(StatementType statementType) { switch (statementType) { case SELECT: return queryHandler; case INSERT: return insertHandler; case UPDATE: return updateHandler; case DELETE: return deleteHandler; default: break; } return null; }...
5.集成Mybatis:
因为Mybatis获取连接是通过PooledDataSource或UnpooledDataSource获取的,所以写个插件:包装下DataSource,把oceanus的connentionWrap包装进去即可实现整合。
oceanus-58总体框架理解相关推荐
- ROS探索总结(一)(二)(三):ROS总体框架 ROS总体框架 ROS新手教程
ROS探索总结(一)--ROS简介 一.历史 随着机器人领域的快速发展和复杂化,代码的复用性和模块化的需求原来越强烈,而已有的开源机器人系统又不能很好的适应需求.2010年Willow Garage公 ...
- 《机械制造业智能工厂规划设计》——第3章 机械制造业智能工厂的总体框架 3.1 智能制造的通用定义和特征...
第3章 机械制造业智能工厂的总体框架 3.1 智能制造的通用定义和特征 1.智能制造的定义和内涵 智能制造系统(Intelligent Manufacturing System,IMS)是一种由智能机 ...
- 从零开始搭建ROS移动机器人系列之(一)预备知识及总体框架
" 笔者2020年初次接触ROS,2021年参加工作以后,愈发对ROS产生浓厚的兴趣,渴望拥有一台ROS机器人,淘宝上一搜再搜,发现有很多现成的产品,但是价格属实让人望而却步,遂产生了自己搭 ...
- 从Netflix的Hystrix框架理解服务熔断和服务降级
本文讲的是从Netflix的Hystrix框架理解服务熔断和服务降级,伴随着微服务架构被宣传得如火如荼,一些概念也被推到了我们面前,其实大多数概念以前就有,但很少被提的这么频繁.想起有人总结的一句话, ...
- 城市大脑标准体系与评价指标总体框架研究
来源:城市大脑全球标准研究组 根据城市大脑标准的前期研究和中国指挥与控制学会(CICC)<城市大脑建设规范>标准启动会的专家意见,形成城市大脑标准体系与评价指标总体框架(如图1所示),供各 ...
- 企业档案信息化规划总体框架
按照<中华人民共和国档案法><企业档案管理规定><企业档案工作规范><企业数字档案馆(室)建设指南>等政策文件要求,企业档案信息化建设应从基础设施体系. ...
- 蜂鸟E203学习笔记(二)--蜂鸟E203总体框架
蜂鸟E203总体框架 蜂鸟E203处理器系统如下图所示 一.蜂鸟E203处理器核设计总览和顶层 1.1 蜂鸟E203处理器核的设计理念 模块化和可重用性:将处理器分成几个主体模块,每个单元之间的接口简 ...
- ZigBee Silicon Labs/Ember EFR32MG/EM357 1.1 总体框架
开启ZigBee新篇章,陆续更新,欢迎关注~ 第一章 总体框架 (已发布 V1 20180201)ZigBee Silicon Labs/Ember EFR32MG/EM357 1.1 总体框架(&l ...
- 理想智慧社区建设的总体框架
导读: 理想智慧社区是未来现代化城市的细胞,也是未来城市的缩影,但它相较城市范围较小,便于试点.理想智慧社区建设为社区有机更新指引了一个新的方向,重点关注人民美好生活需要.基层现代化治理和商业服务模式 ...
最新文章
- python 文字转语音
- Qt 控制watchdog app hacking
- js实现语音播报功能
- 棋牌游戏服务器架构: 详细设计(二) 应用层设计
- 4月21日会议总结(整理—祁子梁)
- 修改tomcat服务器图标,修改tomcat小猫图标,设置项目的favicon图标
- freemarker中运算符_freemarker常见语法大全
- tornado异步客户端(Future)
- 记一次css载入指定url失败
- leetcode 240. 搜索二维矩阵 II
- struts2中的action获取web资源
- C语言———求”完数“
- linux怎么下载ftp文件夹,命令行 - 如何在Linux上通过FTP递归下载文件夹
- java实习收获与体会_java实习心得体会.doc
- 中国历代更改重复地名及其现实意义
- 【渗透测试笔记】之【Cobalt Strike小技巧——后台挂起CS服务端】
- cubic与bbr性能实测
- Es6常见面试题必看!
- 一个人到过的12个国家,45座城市
- 最小二乘法、加权最小二乘法——直线拟合
热门文章
- set_input_delay/set_output_delay
- Percona-toolkit工具详解
- 使用cordova + vue搭建混合app框架
- Node 开发npm脚手架(类似vue-cli)
- 【程序】STM32H743ZI单片机驱动DP83848以太网PHY芯片,移植lwip 2.1.3协议栈,并加入网线热插拔检测的功能
- linux 中的DNS服务
- 李克用置酒三垂冈赋——刘翰(清)
- TextView显示省略号问题
- linux升级n卡驱动,Centos 7 更新 NVIDIA 驱动
- phpstorm破解后,运行一段时间后突然有提示没有破解.