用 Calcite 解决造数时的数据源适配问题
作者:朱志平 编辑:毕小烦
在业务逻辑相同的情况下,如果要让业务系统运行在不同的数据库环境中,如 Oracle、MySQL、TDSQL 等,这不仅对开发来说是一个挑战,对于测试造数来说也同样是一个挑战,这要我们熟悉不同的数据库方言,同样的逻辑要用不同的 SQL 重复写。
怎么解决这个痛点呢?
可以试试 Apache Calcite。
Apache Calcite
Apache Calcite 是一个用于构建数据库和数据管理系统的开源框架。它包括一个 SQL 解析器,一个用于建立关系代数表达式的 API,以及一个查询规划引擎。作为一个框架,Calcite 并不存储自己的数据或元数据,而是允许通过插件的方式访问外部数据和元数据。
Calcite 的主要功能:SQL 解析、校验、查询优化、SQL 生成器和数据连接。
使用 Calcite 可以将各种 SQL 语句解析成抽象语法树 AST(Abstract Syntax Tree),之后通过操作 AST 就可以把 SQL 中所要表达的算法与关系体现在具体代码之中。
Calcite 架构图:
Calcite 的优点是:
一个解析计划适合所有数据库。 支持多数据模型,支持流式数据处理和传统数据处理的查询优化与查询语句。 灵活的查询优化器,每个组件属于插拔式,可扩展。适用于规则优化与成本优化模式。 跨系统支持。 支持 ANSI 的标准 SQL 及相应数据库方言。
我们使用 Calcite,通过对不同的数据库进行方言匹配,达到统一入口转成数据库特有的 SQL 模式。
例如:
当我们想生成类似 select 语句查出来的目标数据时,select 语句要针对不同数据库写多条,insert 或 update 语句也要写多条。可如果使用 calcite sql 增加一层 SQL 适配处理,则只需要写一条 selelct 语句,会匹配出多条 insert 不同数据库方言的 SQL。
方言匹配的逻辑可以用如下代码实现:
public ResultVo parseSql(SqlTextVo sqlVo) {
if (sqlVo == null) {
resultVo.setParseSuccess(false);
resultVo.setMessage("传入sql为空");
return resultVo;
}
String dbType = sqlVo.getDbType().toUpperCase();
SqlParser.Config config = SqlParser.config();
// config.withParserFactory(SqlDdlParserImpl.FACTORY);
config.withCaseSensitive(false);
switch (dbType) {
case "MYSQL":
config.withLex(Lex.MYSQL);
config.withConformance(SqlConformanceEnum.MYSQL_5);
break;
case "ORACLE":
config.withLex(Lex.ORACLE);
config.withConformance(SqlConformanceEnum.ORACLE_10);
break;
default: break;
}
...
}
小结
Calcite 提供了非常丰富的可扩展接口,帮我们实现了扩展数据源、扩展 SQL 查询语法、扩展数据处理引擎等功能,如果你也要准备测试数据,也有类似的痛点,不妨试一试。
(完)
推荐阅读
如果你想玩转 Dubbo 接口测试?一定要知道这 3 种姿势
如果文章对你有帮助,记得留言、点赞、加关注哦!