Appearance
15 扩展机制
15.1 自定义复杂SQL处理机制
15.1.1 功能说明
LIBRA目前并不能处理所有的SQL,有些限制已经在前面的章节介绍,开发者可根据具体的情况通过扩展接口完成功能的实现。但是这对开发人员有一定的要求,需要对LIBRA内部代码有一定的熟悉度,知道怎么使用LIBRA的内部资源。下面只说明怎么来完成扩展与使用。
LIBRA内部定义了一个叫LIBRAlet的接口,接口内的方法可以获取到锁需要的连接与配置信息,开发人员只需要在此基础上实现该接口完成功能逻辑的编写即可,实现类可以在服务中动态加载,通过hint的方式让SQL进入扩展实现的流程。使用方式如下:
sql
/*!LIBRA:{'LIBRAlet':'com.actiontech.dble.extend.InsertSelectLIBRAlet'}*/insert into table1 select * from table2
上述的“com.actiontech.dble.extend.InsertSelectLIBRAlet”就是自定义的扩展实现。
15.1.2 Demo说明
在LIBRA中已经有一个扩展demo,下面大概说一下
15.1.2.1 LIBRAlet接口
java
public interface LIBRAlet {
void execute(SchemaConfig schemaConfig, Boolean runOnSlave, String sql, ServerConnection sc);
}
接口中定义了一个方法作为执行入口并提供所需的所有资源:
- schemaConfig:LIBRA逻辑库的配置信息;
- runOnSlave:是否可以在读节点执行,如果是查询操作可以在读节点执行,减轻写节点的压力;
- sql:hint后面真正的执行sql;
- sc:前端连接处理类,除了前端设置的参数信息还有很多必须的信息,比如在这里存放后端session以及前端的连接通道。
15.1.2.2 Demo类
com.actiontech.dble.extend.InsertSelectLIBRAlet这个类是对"insert into ... select ..."语句的功能实现,下面对主要的处理环节已添加注释说明。
java
try {
SQLStatement sqlStatement = SQLUtils.parseStatements(sql, dbType).get(0);
//在此完成语法解析
if (sqlStatement instanceof SQLInsertStatement){
SQLInsertStatement insertStatement = (SQLInsertStatement)sqlStatement;
String table = insertStatement.getTableName().getSimpleName();
//从解析器中提取表名
if (insertStatement.getQuery() != null){
String selectSql = SQLUtils.toSQLString(insertStatement.getQuery(),dbType);
RouteResultset rrs = DbleServer.getInstance().getRouterService().route(schemaConfig,ServerParse.SELECT,selectSql,sc);
//提取子查询语句并完成路由,rrs中存放着路由节点以及每个节点的执行sql
if (rrs == null || rrs.getNodes() == null || rrs.getNodes().length == 0 || rrs.isNeedOptimizer()){
errorReturn("not support yet!",sc);
}
else {
rrs.setRunOnSlave(runOnSlave);
insertStatement.setQuery(null);
List<SQLExpr> columns = insertStatement.getColumns();
if (columns == null || columns.size() <= 0){
StructureMeta.TableMeta orgTbMeta = DbleServer.getInstance().getTmManager().getSyncTableMeta(schemaConfig.getName(), table);
if (orgTbMeta != null){
List<com.actiontech.dble.meta.protocol.StructureMeta.ColumnMeta> columnMetas = orgTbMeta.getColumnsList();
for (StructureMeta.ColumnMeta columnMeta : columnMetas){
insertStatement.addColumn(new SQLIdentifierExpr(columnMeta.getName()));
}
}
else {
errorReturn("table " + table + " not exist!",sc);
}
}
//以上这段是insert如果没有指定列则从元数据中获取表结构获取列字段并生成insert语句
int columnSize = insertStatement.getColumns().size();
SQLInsertStatement.ValuesClause valuesClause = new SQLInsertStatement.ValuesClause();
for (int i = 0 ; i < columnSize; i++){
SQLVariantRefExpr variantRefExpr = new SQLVariantRefExpr("?");
variantRefExpr.setIndex(i);
valuesClause.addValue(variantRefExpr);
}
//这里是将insert处理成预编译语句
insertStatement.setValues(valuesClause);
InsertSelectHandler insertSelectHandler = new InsertSelectHandler(schemaConfig, rrs,insertStatement,sc);
insertSelectHandler.execute();
}
}
//这里就进入了语句的处理类,在这个handler中完成了select语句结果的处理,insert语句的执行反馈以及将结果返回前端的处理
else {
errorReturn("need insert select statement!",sc);
}
}
else {
errorReturn("need insert select statement!",sc);
}
}