Skip to content

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);
}

​ 接口中定义了一个方法作为执行入口并提供所需的所有资源:

  1. schemaConfig:LIBRA逻辑库的配置信息;
  2. runOnSlave:是否可以在读节点执行,如果是查询操作可以在读节点执行,减轻写节点的压力;
  3. sql:hint后面真正的执行sql;
  4. 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);
            }
        }