嗯,我写了个demo,基本想法是这样的,当sql长度大于1K且是insert语句,我就转到另外一个方法里去处理;这个方法采用druid解析,把druid解析的结果转成antlr4解析的结果,再交给sharding去处理;但是我对sharding代码很不熟悉,我觉得适配性会很差 ,但目前在公司项目里测试也还够用 ,比原先的快8到10倍,解析时间。
代码如下:
public final class SQLStatementParserExecutor {
//......
public SQLStatement parse(final String sql) {
if (sql.length() > 1024 && ("insert".equals(sql.trim().substring(0, 6)) || "INSERT".equals(sql.trim().substring(0, 6))) ) {
log.info("你进入的是Druid SQL parser");
return druidPar(sql);
}
SQLStatement sqlStatement = visitorEngine.visit(parserEngine.parse(sql, false));
return visitorEngine.visit(parserEngine.parse(sql, false));
}
public SQLStatement druidPar(final String sql) {
//druid
MySqlStatementParser druidParser = new MySqlStatementParser(sql);
com.powersi.sqlparser.sql.ast.SQLStatement druidSQLStatement = druidParser.parseStatement();
MySqlInsertStatement insert = (MySqlInsertStatement)druidSQLStatement;
SQLExprTableSource tableSource = insert.getTableSource();
String tableName = insert.getTableSource().getTableName();
List<SQLExpr> columns = insert.getColumns();
// 子查询
SQLSelect query = insert.getQuery();
//如果有子查询,则全部交给sharding
if (query != null){
return visitorEngine.visit(parserEngine.parse(sql, false));
}
List<SQLInsertStatement.ValuesClause> valuesList = insert.getValuesList();
List<SQLExpr> values = valuesList.get(0).getValues();
MySQLInsertStatement insertStatement = new MySQLInsertStatement();
//替换setAssignment
replaceAssignment(insertStatement);
//替换setOnDuplicateKeyColumns
replaceOnDuplicatekeyColumns(insertStatement);
//替换table
replaceTable(tableSource, tableName, insertStatement);
//替换insertColumns
replaceInsertColumns(insert, columns, insertStatement);
//替换insertSelect
replaceInsertSelect(insertStatement);
//替换values
replaceValues(valuesList, values, insertStatement);
//替换parameterCount
replaceParameterCount(insertStatement);
//替换commentSegments
replaceCommentSegments(insertStatement);
return insertStatement;
}
//替换values
private void replaceValues(List<SQLInsertStatement.ValuesClause> valuesList, List<SQLExpr> values, MySQLInsertStatement insertStatement) {
int valuesListSize = valuesList.size();
int valuesSize = values.size();
List<List<ExpressionSegment>> expressionSegmentsList = new LinkedList<>();
ExpressionSegment expressionSegment = null;
//记录起始位置
int valuesStartIndex;
//记录结束位置
int valuesStopIndex;
InsertValuesSegment insertValuesSegment = null;
//遍历插入的记录
for (int i = 0; i < valuesListSize; i++) {
valuesStartIndex = valuesList.get(i).getStartIndex();
valuesStopIndex = valuesList.get(i).getEndIndex();
List<ExpressionSegment> expressionSegments = new LinkedList<>();
//遍历每条插入记录里的字段值
for (int j = 0;j < valuesSize;j++){
expressionSegments.add(null);
SQLExpr sqlExpr = valuesList.get(i).getValues().get(j);
if (sqlExpr instanceof SQLNullExpr){
expressionSegment = new CommonExpressionSegment(sqlExpr.getStartIndex(), sqlExpr.getEndIndex(), sqlExpr.toString());
} else if (sqlExpr instanceof SQLValuableExpr){
expressionSegment = new LiteralExpressionSegment(sqlExpr.getStartIndex(), sqlExpr.getEndIndex(), ((SQLValuableExpr) sqlExpr).getValue());
} else {
throw new RuntimeException("这个值是未知类型-->" + "valuesListSize:" + i + "valuesSize:" + j );
}
expressionSegments.set(j,expressionSegment);
}
expressionSegmentsList.add(expressionSegments);
insertValuesSegment = new InsertValuesSegment(valuesStartIndex, valuesStopIndex, expressionSegmentsList.get(i));
insertStatement.getValues().add(insertValuesSegment);
}
}
//替换insertColumns
private void replaceInsertColumns(MySqlInsertStatement insert, List<SQLExpr> columns, MySQLInsertStatement insertStatement) {
int columnsStartIndex;
int columnsStopIndex;
LinkedList<ColumnSegment> columnList = null;
if (columns.size() == 0){
columnList = new LinkedList<>();
columnsStartIndex = columnsStopIndex = insert.getColumnIndex(VALUES) - 1;
}else {
ColumnSegment column = null;
columnList = new LinkedList<>();
//左括号的位置
columnsStartIndex = insert.getColumnIndex(LPAREN);
//右括号的位置
columnsStopIndex = insert.getColumnIndex(RPAREN);
for (SQLExpr sqlExpr : columns) {
//判断字段名是否带了反引号
if (sqlExpr.isBackticks()){
column = new ColumnSegment(sqlExpr.getStartIndex(), sqlExpr.getEndIndex(), new IdentifierValue(sqlExpr.toString(), QuoteCharacter.BACK_QUOTE));
}else {
column = new ColumnSegment(sqlExpr.getStartIndex(), sqlExpr.getEndIndex(), new IdentifierValue(sqlExpr.toString(), QuoteCharacter.NONE));
}
columnList.add(column);
}
}
InsertColumnsSegment insertColumnsSegment = new InsertColumnsSegment(columnsStartIndex, columnsStopIndex, columnList);
insertStatement.setInsertColumns(insertColumnsSegment);
}
//替换table
private void replaceTable(SQLExprTableSource tableSource, String tableName, MySQLInsertStatement insertStatement) {
int tableStartIndex = tableSource.getExpr().getStartIndex();
int tableStopIndex = tableSource.getExpr().getEndIndex();
// 判断表名是否带了反引号
if (tableSource.getExpr().isBackticks()){
IdentifierValue table = new IdentifierValue(tableName, QuoteCharacter.BACK_QUOTE);
TableNameSegment tableNameSegment = new TableNameSegment(tableStartIndex,tableStopIndex,table);
SimpleTableSegment simpleTableSegment = new SimpleTableSegment(tableNameSegment);
insertStatement.setTable(simpleTableSegment);
}else {
IdentifierValue table = new IdentifierValue(tableName, QuoteCharacter.NONE);
TableNameSegment tableNameSegment = new TableNameSegment(tableStartIndex,tableStopIndex,table);
SimpleTableSegment simpleTableSegment = new SimpleTableSegment(tableNameSegment);
insertStatement.setTable(simpleTableSegment);
}
}