作者:朱志平 编辑:毕小烦

在业务逻辑相同的情况下,如果要让业务系统运行在不同的数据库环境中,如 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 架构图:
image.png
Calcite 的优点是:

  1. 一个解析计划适合所有数据库。
  2. 支持多数据模型,支持流式数据处理和传统数据处理的查询优化与查询语句。
  3. 灵活的查询优化器,每个组件属于插拔式,可扩展。适用于规则优化与成本优化模式。
  4. 跨系统支持。
  5. 支持 ANSI 的标准 SQL 及相应数据库方言。

我们使用 Calcite,通过对不同的数据库进行方言匹配,达到统一入口转成数据库特有的 SQL 模式。

例如:

当我们想生成类似 select 语句查出来的目标数据时,select 语句要针对不同数据库写多条,insert 或 update 语句也要写多条。可如果使用 calcite sql 增加一层 SQL 适配处理,则只需要写一条 selelct 语句,会匹配出多条 insert 不同数据库方言的 SQL。

方言匹配的逻辑可以用如下代码实现:

  1. public ResultVo parseSql(SqlTextVo sqlVo) {
  2. if (sqlVo == null) {
  3. resultVo.setParseSuccess(false);
  4. resultVo.setMessage("传入sql为空");
  5. return resultVo;
  6. }
  7. String dbType = sqlVo.getDbType().toUpperCase();
  8. SqlParser.Config config = SqlParser.config();
  9. // config.withParserFactory(SqlDdlParserImpl.FACTORY);
  10. config.withCaseSensitive(false);
  11. switch (dbType) {
  12. case "MYSQL":
  13. config.withLex(Lex.MYSQL);
  14. config.withConformance(SqlConformanceEnum.MYSQL_5);
  15. break;
  16. case "ORACLE":
  17. config.withLex(Lex.ORACLE);
  18. config.withConformance(SqlConformanceEnum.ORACLE_10);
  19. break;
  20. default: break;
  21. }
  22. ...
  23. }

小结

Calcite 提供了非常丰富的可扩展接口,帮我们实现了扩展数据源、扩展 SQL 查询语法、扩展数据处理引擎等功能,如果你也要准备测试数据,也有类似的痛点,不妨试一试。

(完)

微信搜索“毕小烦”或者扫描下面的二维码,即可订阅我的微信公众号

image.png
如果文章对你有帮助,记得留言、点赞、加关注哦!