Mycat 源码修改-实现分表规则:按天和取摸功能。之前修改过源码,发现其实没什么高深的只需要自己耐心点,多花点时间去调试就可以做到了。通过调试,找到自己想要改的地方,这是关键的:在代码中表现为修改相应的配置规则、相关的路由直达问题。按天分表的在我的前一篇博客(Mycat 开发调试环境配置-开启二次开发之路)中有讲述,只是这里的规则改了下,所以不再主讲按天分表。这里重点讲的是取摸分表查询。
private final String subTables;
private final String subTableWay;
private final String deliveryField;
public TableConfig(String name, String primaryKey, boolean autoIncrement,boolean needAddLimit, int tableType,
String dataNode,Set dbType, RuleConfig rule, boolean ruleRequired,
TableConfig parentTC, boolean isChildTable, String joinKey,
String parentKey,String subTables,String subTableWay,String deliveryField) {
if (name == null) {
throw new IllegalArgumentException("table name is null");
} else if (dataNode == null) {
throw new IllegalArgumentException("dataNode name is null");
}
this.subTables=subTables;
this.subTableWay=subTableWay;
this.deliveryField=deliveryField;
this.primaryKey = primaryKey;
this.autoIncrement = autoIncrement;
this.needAddLimit=needAddLimit;
this.tableType = tableType;
this.dbTypes=dbType;
if (ruleRequired && rule == null) {
throw new IllegalArgumentException("ruleRequired but rule is null");
}
this.name = name.toUpperCase();
String theDataNodes[] = SplitUtil.split(dataNode, ',', '$', '-');
if (theDataNodes == null || theDataNodes.length <= 0) {
throw new IllegalArgumentException("invalid table dataNodes: " + dataNode);
}
dataNodes = new ArrayList(theDataNodes.length);
for (String dn : theDataNodes) {
dataNodes.add(dn);
}
if(subTables!=null && !subTables.equals("")){
if(subTableWay==null ||subTableWay.equals("")||subTableWay.equals("DEFAULT")){
// 原始按顺序分表方式
String sTables[] = SplitUtil.split(subTables, ',', '$', '-');
if (sTables == null || sTables.length <= 0) {
throw new IllegalArgumentException("invalid table subTables");
}
this.distTables = new ArrayList(sTables.length);
for (String table : sTables) {
LOGGER.info("默认分表信息——dataNode:"+dataNode+",table:"+table);
distTables.add(table);
}
}else if(subTableWay.equals("BYDELIVERY")){
// 取摸分表方式
String sTables[] = SplitUtil.split(subTables, ',', '$', '-');
if (sTables == null || sTables.length <= 0) {
throw new IllegalArgumentException("invalid table subTables");
}
if(deliveryField==null||deliveryField.equals("")){
throw new IllegalArgumentException("invalid table deliveryField");
}
this.distTables = new ArrayList(sTables.length);
for (String table : sTables) {
LOGGER.info("取摸分表信息——dataNode:"+dataNode+",table:"+table);
distTables.add(table);
}
}else if(subTableWay.equals("BYDATE")){
// 按日分表方式
String str=subTables.substring(subTables.indexOf("$")+1, subTables.length());
String splitChar="-";
if(str==null||str.length() <= 0||!str.contains(splitChar)){
throw new IllegalArgumentException("invalid table subTables:you should set date like $20170717-20180716 or $20170717-?");
}
String [] strDates=str.split("-");
if(strDates.length!=2) {
throw new IllegalArgumentException("invalid table subTables:you should set date like $20170717-20180716 or $20170717-?");
}
String dateStart=strDates[0];//开始日期
String dateEnd=strDates[1];// 结束日期
if(dateStart.equals(dateEnd)){
throw new IllegalArgumentException("invalid table subTables:you should set date like $20170717-20180716 or $20170717-?");
}
String dateFormat="yyyyMMdd";
Date begin=null;
Date end=null;
try {
begin=DateUtils.parseDate(dateStart, dateFormat);
end=DateUtils.parseDate(dateEnd.equals("?")?DateUtils.getStrFormTime(dateFormat, new Date()):dateEnd, dateFormat);
} catch (ParseException e) {
throw new IllegalArgumentException("invalid table subTables:you should set date like $20170717-20180716 or $20170717-?");
}
if(begin.getTime()>end.getTime()){
throw new IllegalArgumentException("invalid table subTables:start date can't bigger than end date");
}
// 生成对应的按日期表集合
List dates=DateUtils.getBetweenDates(begin, end);
this.distTables = new ArrayList(dates.size());
String tablePrex=subTables.substring(0, subTables.indexOf("$"));
for (Date date : dates) {
String table=tablePrex+DateUtils.getStrFormTime(dateFormat, date);
LOGGER.info("按天分表信息——dataNode:"+dataNode+",table:"+table);
distTables.add(table);
}
}else{
throw new IllegalArgumentException("invalid table subTableWay");
}
}else{
this.distTables = new ArrayList();
}
this.rule = rule;
this.partitionColumn = (rule == null) ? null : rule.getColumn();
partionKeyIsPrimaryKey=(partitionColumn==null)?primaryKey==null:partitionColumn.equals(primaryKey);
this.ruleRequired = ruleRequired;
this.childTable = isChildTable;
this.parentTC = parentTC;
this.joinKey = joinKey;
this.parentKey = parentKey;
if (parentTC != null) {
locateRTableKeySql = genLocateRootParentSQL();
secondLevel = (parentTC.parentTC == null);
} else {
locateRTableKeySql = null;
secondLevel = false;
}
}
注:建议构造重写,构造函数涉及io.mycat.config.loader.xml.XMLSchemaLoader.java类的修改。
新增属性字段:subTableWay和deliveryField
select user()
据下图进行一步步分析 :
public RouteResultset routeNormalSqlWithAST(SchemaConfig schema,
String stmt, RouteResultset rrs, String charset,
LayerCachePool cachePool) throws SQLNonTransientException {
/**
* 只有mysql时只支持mysql语法
*/
SQLStatementParser parser = null;
if (schema.isNeedSupportMultiDBType()) {
parser = new MycatStatementParser(stmt);
} else {
parser = new MySqlStatementParser(stmt);
}
MycatSchemaStatVisitor visitor = null;
SQLStatement statement;
/**
* 解析出现问题统一抛SQL语法错误
*/
try {
statement = parser.parseStatement();
visitor = new MycatSchemaStatVisitor();
} catch (Exception t) {
LOGGER.error("DruidMycatRouteStrategyError", t);
throw new SQLSyntaxErrorException(t);
}
/**
* 检验unsupported statement
*/
checkUnSupportedStatement(statement);
DruidParser druidParser = DruidParserFactory.create(schema, statement, visitor);
druidParser.parser(schema, rrs, statement, stmt,cachePool,visitor);
/**
* DruidParser 解析过程中已完成了路由的直接返回
*/
if ( rrs.isFinishedRoute() ) {
return rrs;
}
/**
* 没有from的select语句或其他
*/
DruidShardingParseInfo ctx= druidParser.getCtx() ;
if((ctx.getTables() == null || ctx.getTables().size() == 0)&&(ctx.getTableAliasMap()==null||ctx.getTableAliasMap().isEmpty()))
{
return RouterUtil.routeToSingleNode(rrs, schema.getRandomDataNode(), druidParser.getCtx().getSql());
}
if(druidParser.getCtx().getRouteCalculateUnits().size() == 0) {
RouteCalculateUnit routeCalculateUnit = new RouteCalculateUnit();
druidParser.getCtx().addRouteCalculateUnit(routeCalculateUnit);
}
SortedSet nodeSet = new TreeSet();
for(RouteCalculateUnit unit: druidParser.getCtx().getRouteCalculateUnits()) {
RouteResultset rrsTmp = RouterUtil.tryRouteForTables(schema, druidParser.getCtx(), unit, rrs, isSelect(statement), cachePool);
if(rrsTmp != null) {
for(RouteResultsetNode node :rrsTmp.getNodes()) {
nodeSet.add(node);
}
}
}
RouteResultsetNode[] nodes = new RouteResultsetNode[nodeSet.size()];
int i = 0;
for (RouteResultsetNode aNodeSet : nodeSet) {
nodes[i] = aNodeSet;
if(statement instanceof MySqlInsertStatement &&ctx.getTables().size()==1&&schema.getTables().containsKey(ctx.getTables().get(0))) {
RuleConfig rule = schema.getTables().get(ctx.getTables().get(0)).getRule();
if(rule!=null&& rule.getRuleAlgorithm() instanceof SlotFunction){
aNodeSet.setStatement(ParseUtil.changeInsertAddSlot(aNodeSet.getStatement(),aNodeSet.getSlot()));
}
}
i++;
}
rrs.setNodes(nodes);
//分表
/**
* subTables="t_order$1-2,t_order3"
*目前分表 1.6 开始支持 幵丏 dataNode 在分表条件下只能配置一个,分表条件下不支持join。
*/
if(rrs.isDistTable()){
return this.routeDisTable(statement,rrs);
}
return rrs;
}
for(RouteCalculateUnit unit: druidParser.getCtx().getRouteCalculateUnits()) {
RouteResultset rrsTmp = RouterUtil.tryRouteForTables(schema, druidParser.getCtx(), unit, rrs, isSelect(statement), cachePool);
if(rrsTmp != null) {
for(RouteResultsetNode node :rrsTmp.getNodes()) {
nodeSet.add(node);
}
}
}
/**
* 多表路由
*/
public static RouteResultset tryRouteForTables(SchemaConfig schema, DruidShardingParseInfo ctx,
RouteCalculateUnit routeUnit, RouteResultset rrs, boolean isSelect, LayerCachePool cachePool)
throws SQLNonTransientException {
List tables = ctx.getTables();
if(schema.isNoSharding()||(tables.size() >= 1&&isNoSharding(schema,tables.get(0)))) {
if(Pattern.matches(".*_201\\d{5,5}", tables.get(0))){//支持分表, t_location_20170704这种表,删除结尾的_20170704后再查找路由
TableConfig tc=schema.getTables().get( tables.get(0).substring(0, tables.get(0).length()-9));
return routeToSingleNode(rrs, tc.getDataNodes().get(0), ctx.getSql());
}
return routeToSingleNode(rrs, schema.getDataNode(), ctx.getSql());
}
//只有一个表的
if(tables.size() == 1) {
return RouterUtil.tryRouteForOneTable(schema, ctx, routeUnit, tables.get(0), rrs, isSelect, cachePool);
}
Set retNodesSet = new HashSet();
//每个表对应的路由映射
Map> tablesRouteMap = new HashMap>();
//分库解析信息不为空
Map>> tablesAndConditions = routeUnit.getTablesAndConditions();
if(tablesAndConditions != null && tablesAndConditions.size() > 0) {
//为分库表找路由
RouterUtil.findRouteWithcConditionsForTables(schema, rrs, tablesAndConditions, tablesRouteMap, ctx.getSql(), cachePool, isSelect);
if(rrs.isFinishedRoute()) {
return rrs;
}
}
//为全局表和单库表找路由
for(String tableName : tables) {
TableConfig tableConfig = schema.getTables().get(tableName.toUpperCase());
if(tableConfig==null && Pattern.matches(".*_201\\d{5,5}", tableName)){//支持分表, t_location_20170704这种表,支持结尾的_20170704后再查找路由
tableConfig=schema.getTables().get(tableName.substring(0, tableName.length()-9));
}
if(tableConfig == null) {
String msg = "can't find table define in schema "+ tableName + " schema:" + schema.getName();
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
if(tableConfig.isGlobalTable()) {//全局表
if(tablesRouteMap.get(tableName) == null) {
tablesRouteMap.put(tableName, new HashSet());
}
tablesRouteMap.get(tableName).addAll(tableConfig.getDataNodes());
} else if(tablesRouteMap.get(tableName) == null) { //余下的表都是单库表
tablesRouteMap.put(tableName, new HashSet());
tablesRouteMap.get(tableName).addAll(tableConfig.getDataNodes());
}
}
boolean isFirstAdd = true;
for(Map.Entry> entry : tablesRouteMap.entrySet()) {
if(entry.getValue() == null || entry.getValue().size() == 0) {
throw new SQLNonTransientException("parent key can't find any valid datanode ");
} else {
if(isFirstAdd) {
retNodesSet.addAll(entry.getValue());
isFirstAdd = false;
} else {
retNodesSet.retainAll(entry.getValue());
if(retNodesSet.size() == 0) {//两个表的路由无交集
String errMsg = "invalid route in sql, multi tables found but datanode has no intersection "
+ " sql:" + ctx.getSql();
LOGGER.warn(errMsg);
throw new SQLNonTransientException(errMsg);
}
}
}
}
if(retNodesSet != null && retNodesSet.size() > 0) {
String tableName = tables.get(0);
TableConfig tableConfig = schema.getTables().get(tableName.toUpperCase());
if(tableConfig==null && Pattern.matches(".*_201\\d{5,5}", tableName)){//支持分表, t_location_20170704这种表,支持结尾的_20170704后再查找路由
tableConfig=schema.getTables().get(tableName.substring(0, tableName.length()-9));
}
if(tableConfig.isDistTable()){
routeToDistTableNode(tableName,schema, rrs, ctx.getSql(), tablesAndConditions, cachePool, isSelect);
return rrs;
}
if(retNodesSet.size() > 1 && isAllGlobalTable(ctx, schema)) {
// mulit routes ,not cache route result
if (isSelect) {
rrs.setCacheAble(false);
routeToSingleNode(rrs, retNodesSet.iterator().next(), ctx.getSql());
}
else {//delete 删除全局表的记录
routeToMultiNode(isSelect, rrs, retNodesSet, ctx.getSql(),true);
}
} else {
routeToMultiNode(isSelect, rrs, retNodesSet, ctx.getSql());
}
}
return rrs;
}
/**
*
* 单表路由
*/
public static RouteResultset tryRouteForOneTable(SchemaConfig schema, DruidShardingParseInfo ctx,
RouteCalculateUnit routeUnit, String tableName, RouteResultset rrs, boolean isSelect,
LayerCachePool cachePool) throws SQLNonTransientException {
if (isNoSharding(schema, tableName)) {
return routeToSingleNode(rrs, schema.getDataNode(), ctx.getSql());
}
TableConfig tc = schema.getTables().get(tableName);
if(Pattern.matches(".*_201\\d{5,5}", tableName)){//支持分表, t_location_20170704这种表,删除结尾的_20170704后再查找路由
tc=schema.getTables().get(tableName.substring(0, tableName.length()-9));
}
if(tc == null) {
String msg = "can't find table define in schema " + tableName + " schema:" + schema.getName();
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
if(tc.isDistTable()){
return routeToDistTableNode(tableName,schema,rrs,ctx.getSql(), routeUnit.getTablesAndConditions(), cachePool,isSelect);
}
if(tc.isGlobalTable()) {//全局表
if(isSelect) {
// global select ,not cache route result
rrs.setCacheAble(false);
return routeToSingleNode(rrs, tc.getRandomDataNode(),ctx.getSql());
} else {//insert into 全局表的记录
return routeToMultiNode(false, rrs, tc.getDataNodes(), ctx.getSql(),true);
}
} else {//单表或者分库表
if (!checkRuleRequired(schema, ctx, routeUnit, tc)) {
throw new IllegalArgumentException("route rule for table "
+ tc.getName() + " is required: " + ctx.getSql());
}
if(tc.getPartitionColumn() == null && !tc.isSecondLevel()) {//单表且不是childTable
// return RouterUtil.routeToSingleNode(rrs, tc.getDataNodes().get(0),ctx.getSql());
return routeToMultiNode(rrs.isCacheAble(), rrs, tc.getDataNodes(), ctx.getSql());
} else {
//每个表对应的路由映射
Map> tablesRouteMap = new HashMap>();
if(routeUnit.getTablesAndConditions() != null && routeUnit.getTablesAndConditions().size() > 0) {
RouterUtil.findRouteWithcConditionsForTables(schema, rrs, routeUnit.getTablesAndConditions(), tablesRouteMap, ctx.getSql(), cachePool, isSelect);
if(rrs.isFinishedRoute()) {
return rrs;
}
}
if(tablesRouteMap.get(tableName) == null) {
return routeToMultiNode(rrs.isCacheAble(), rrs, tc.getDataNodes(), ctx.getSql());
} else {
return routeToMultiNode(rrs.isCacheAble(), rrs, tablesRouteMap.get(tableName), ctx.getSql());
}
}
}
}
注:重点是if(tc.isDistTable()){ return routeToDistTableNode(tableName,schema,rrs,ctx.getSql(), routeUnit.getTablesAndConditions(), cachePool,isSelect); }
/**
*分表路由处理
*/
private static RouteResultset routeToDistTableNode(String tableName, SchemaConfig schema, RouteResultset rrs,
String orgSql, Map>> tablesAndConditions,
LayerCachePool cachePool, boolean isSelect) throws SQLNonTransientException {
TableConfig tableConfig = schema.getTables().get(tableName);
if(tableConfig == null) {
String msg = "can't find table define in schema " + tableName + " schema:" + schema.getName();
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
if(tableConfig.isGlobalTable()){
String msg = "can't suport district table " + tableName + " schema:" + schema.getName() + " for global table ";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
String partionCol = tableConfig.getPartitionColumn();
// String primaryKey = tableConfig.getPrimaryKey();
boolean isLoadData=false;
Set tablesRouteSet = new HashSet();
List dataNodes = tableConfig.getDataNodes();
if(dataNodes.size()>1){
String msg = "can't suport district table " + tableName + " schema:" + schema.getName() + " for mutiple dataNode " + dataNodes;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
String dataNode = dataNodes.get(0);
//主键查找缓存暂时不实现
if(tablesAndConditions.isEmpty()){
// 取摸查询====开始======
if(tableConfig.getSubTableWay().equals("BYDELIVERY")&&tableConfig.getDeliveryField()!=null&&!tableConfig.getDeliveryField().equals("")){
long vechicleId=-1;
String hintStart="/**";
String hintEnd="**/";
if(!orgSql.contains(hintStart)&&!orgSql.contains(hintEnd)){
String msg = "incorrect sql rule by subTables='BYDELIVERY' property deliveryField='"+tableConfig.getDeliveryField()+"'";
msg+=">>:select SQL would like to end with /**"+tableConfig.getDeliveryField()+"="+108392232+"**/";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}else{
String valueStr=orgSql.substring(orgSql.indexOf(hintStart)+3, orgSql.length()-3);
String [] values=valueStr.split("=");
try {
vechicleId=Long.parseLong(values[1]);
} catch (NumberFormatException e) {
String msg = " subTables='BYDELIVERY' property deliveryField='"+tableConfig.getDeliveryField()+"' value is not a number.";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
if(values.length<2||!tableConfig.getDeliveryField().equalsIgnoreCase(values[0])){
String msg = " subTables='BYDELIVERY' property deliveryField='"+tableConfig.getDeliveryField()+"' is not the same file end with the SQL";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
}
// 取摸方式处理
List subTables = new ArrayList();
int count=tableConfig.getDistTables().size();
String table=tableConfig.getName();
String ruleTable=tableConfig.getSubTables().substring(0,tableConfig.getSubTables().indexOf("$"));
String connectStr=ruleTable.length()==table.length()?"":ruleTable.substring(table.length(), ruleTable.length());
vechicleId=vechicleId%count==0?count:vechicleId%count;
String delvieryTable=new String(table+connectStr+vechicleId).toLowerCase();
for (String subTable : tableConfig.getDistTables()) {
if(subTable.equals(delvieryTable)){
subTables.add(subTable);// 取摸表
}
}
tablesRouteSet.addAll(subTables);
}else{
List subTables = tableConfig.getDistTables();
tablesRouteSet.addAll(subTables);
}
// 取摸查询====结束======
}else{
for(Map.Entry>> entry : tablesAndConditions.entrySet()) {
boolean isFoundPartitionValue = partionCol != null && entry.getValue().get(partionCol) != null;
Map> columnsMap = entry.getValue();
Set partitionValue = columnsMap.get(partionCol);
if(partitionValue == null || partitionValue.size() == 0) {
// 条件取摸方式=========开始====
//tablesRouteSet.addAll(tableConfig.getDistTables());
if(tableConfig.getSubTableWay().equals("BYDELIVERY")&&tableConfig.getDeliveryField()!=null&&!tableConfig.getDeliveryField().equals("")){
long vechicleId=-1;
String hintStart="/**";
String hintEnd="**/";
if(!orgSql.contains(hintStart)&&!orgSql.contains(hintEnd)){
String msg = "incorrect sql rule by subTables='BYDELIVERY' property deliveryField='"+tableConfig.getDeliveryField()+"'";
msg+=">>:select SQL would like to end with /**"+tableConfig.getDeliveryField()+"="+108392232+"**/";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}else{
String valueStr=orgSql.substring(orgSql.indexOf(hintStart)+3, orgSql.length()-3);
String [] values=valueStr.split("=");
try {
vechicleId=Long.parseLong(values[1]);
} catch (NumberFormatException e) {
String msg = " subTables='BYDELIVERY' property deliveryField='"+tableConfig.getDeliveryField()+"' value is not a number.";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
if(values.length<2||!tableConfig.getDeliveryField().equalsIgnoreCase(values[0])){
String msg = " subTables='BYDELIVERY' property deliveryField='"+tableConfig.getDeliveryField()+"' is not the same file end with the SQL";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
}
// 取摸方式处理
List subTables = new ArrayList();
int count=tableConfig.getDistTables().size();
String table=tableConfig.getName();
String ruleTable=tableConfig.getSubTables().substring(0,tableConfig.getSubTables().indexOf("$"));
String connectStr=ruleTable.length()==table.length()?"":ruleTable.substring(table.length(), ruleTable.length());
vechicleId=vechicleId%count==0?count:vechicleId%count;
String delvieryTable=new String(table+connectStr+vechicleId).toLowerCase();
for (String subTable : tableConfig.getDistTables()) {
if(subTable.equals(delvieryTable)){
subTables.add(subTable);// 取摸表
}
}
tablesRouteSet.addAll(subTables);
orgSql=orgSql.substring(0,orgSql.indexOf(hintStart));
}else{
List subTables = tableConfig.getDistTables();
tablesRouteSet.addAll(subTables);
}
// 条件取摸方式=========结束====
} else {
for(ColumnRoutePair pair : partitionValue) {
AbstractPartitionAlgorithm algorithm = tableConfig.getRule().getRuleAlgorithm();
if(pair.colValue != null) {
Integer tableIndex = algorithm.calculate(pair.colValue);
if(tableIndex == null) {
String msg = "can't find any valid datanode :" + tableConfig.getName()
+ " -> " + tableConfig.getPartitionColumn() + " -> " + pair.colValue;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
String subTable = tableConfig.getDistTables().get(tableIndex);
if(subTable != null) {
tablesRouteSet.add(subTable);
if(algorithm instanceof SlotFunction){
rrs.getDataNodeSlotMap().put(subTable,((SlotFunction) algorithm).slotValue());
}
}
}
if(pair.rangeValue != null) {
Integer[] tableIndexs = algorithm
.calculateRange(pair.rangeValue.beginValue.toString(), pair.rangeValue.endValue.toString());
for(Integer idx : tableIndexs) {
String subTable = tableConfig.getDistTables().get(idx);
if(subTable != null) {
tablesRouteSet.add(subTable);
if(algorithm instanceof SlotFunction){
rrs.getDataNodeSlotMap().put(subTable,((SlotFunction) algorithm).slotValue());
}
}
}
}
}
}
}
}
Object[] subTables = tablesRouteSet.toArray();
RouteResultsetNode[] nodes = new RouteResultsetNode[subTables.length];
Map dataNodeSlotMap= rrs.getDataNodeSlotMap();
for(int i=0;i
注:无论有无where查询都是可以的(测试过程中发现错误已修改)。
请对比参考如下两个图:
请对比参考如下两个图:
可见,取摸查询已实现。
这里需要特别注意mysql数据库关键字问题,下面是数据库关键字测试问题:如 name、table、by等等。
下面两个SQL插入语句在Druid解析是有区别的:
-- 正确解析语句
INSERT into t_subtable(_id,title,`name`,`table`,description,likes,`by`) VALUES('59759679dc07a955104a9f1b','mongo','boonya4','t_subtable_4','database','100','boonya') /**vehicle_id=128943434354**/
-- 错误解析语句
INSERT into t_subtable(_id,title,name,table,description,likes,by) VALUES('59759679dc07a955104a9f1b','mongo','boonya4','t_subtable_4','database','100','boonya') /**vehicle_id=128943434354**/
(io.mycat.route.impl.DruidMycatRouteStrategy:DruidMycatRouteStrategy.java:78)
2017-07-25 12:04:25,114 [WARN ][$_NIOREACTOR-1-RW] ServerConnection [id=1, schema=TESTDB, host=192.168.1.7, user=root,txIsolation=3, autocommit=true, schema=TESTDB]INSERT into t_subtable(_id,title,name,table,description,likes,by) VALUES('59759679dc07a955104a9f1b','mongo','boonya4','t_subtable_4','database','100','boonya') /**vehicle_id=128943434354**/ err:java.sql.SQLSyntaxErrorException: com.alibaba.druid.sql.parser.ParserException: ERROR. token : BY, pos : 64 java.sql.SQLSyntaxErrorException: com.alibaba.druid.sql.parser.ParserException: ERROR. token : BY, pos : 64
at io.mycat.route.impl.DruidMycatRouteStrategy.routeNormalSqlWithAST(DruidMycatRouteStrategy.java:79)
at io.mycat.route.impl.AbstractRouteStrategy.route(AbstractRouteStrategy.java:81)
at io.mycat.route.RouteService.route(RouteService.java:133)
at io.mycat.server.ServerConnection.routeEndExecuteSQL(ServerConnection.java:276)
at io.mycat.server.ServerConnection.execute(ServerConnection.java:222)
at io.mycat.server.ServerQueryHandler.query(ServerQueryHandler.java:136)
at io.mycat.net.FrontendConnection.query(FrontendConnection.java:317)
at io.mycat.net.FrontendConnection.query(FrontendConnection.java:337)
at io.mycat.net.handler.FrontendCommandHandler.handle(FrontendCommandHandler.java:71)
at io.mycat.net.FrontendConnection.rawHandle(FrontendConnection.java:478)
at io.mycat.net.FrontendConnection.handle(FrontendConnection.java:460)
at io.mycat.net.AbstractConnection.onReadData(AbstractConnection.java:321)
at io.mycat.net.NIOSocketWR.asynRead(NIOSocketWR.java:190)
at io.mycat.net.AbstractConnection.asynRead(AbstractConnection.java:273)
at io.mycat.net.NIOReactor$RW.run(NIOReactor.java:102)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.alibaba.druid.sql.parser.ParserException: ERROR. token : BY, pos : 64
at com.alibaba.druid.sql.parser.SQLExprParser.primary(SQLExprParser.java:587)
at com.alibaba.druid.sql.dialect.mysql.parser.MySqlExprParser.primary(MySqlExprParser.java:167)
at com.alibaba.druid.sql.parser.SQLExprParser.expr(SQLExprParser.java:94)
at com.alibaba.druid.sql.parser.SQLExprParser.exprList(SQLExprParser.java:903)
at com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser.parseInsert(MySqlStatementParser.java:2014)
at com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser.parseInsert(MySqlStatementParser.java:193)
at com.alibaba.druid.sql.parser.SQLStatementParser.parseStatementList(SQLStatementParser.java:199)
at com.alibaba.druid.sql.parser.SQLStatementParser.parseStatement(SQLStatementParser.java:2065)
at io.mycat.route.impl.DruidMycatRouteStrategy.routeNormalSqlWithAST(DruidMycatRouteStrategy.java:75)
... 15 more
(io.mycat.server.ServerConnection:ServerConnection.java:281)
附录是我摘录可能以后用得着的东西,权当备忘。
如果想了解Mycat路由解析可以参考:Mycat的SQL解析和路由
如果想了解Mycat后端通信模块可以参考:Mycat源码篇 : MyCat线程模型分析
如果想了解Mycat事务管理可以参考:Mycat源码篇 : MyCat事务管理机制分析
如果想了解mycat具体的分片取模可以参考:mycat 取模分片,ER分片
如果想了解Mysql全局序列号可以参考:mycat 使用mysql实现全局序列号