查看原文
其他

用 Calcite 解决造数时的数据源适配问题

朱志平 毕小烦 2022-11-18

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

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

  1. 一个解析计划适合所有数据库。
  2. 支持多数据模型,支持流式数据处理和传统数据处理的查询优化与查询语句。
  3. 灵活的查询优化器,每个组件属于插拔式,可扩展。适用于规则优化与成本优化模式。
  4. 跨系统支持。
  5. 支持 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;
        defaultbreak;
    }
...
}

小结

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

(完)

推荐阅读


如何测试微信公众号?

数据工厂低代码平台探索与实践

我们用到的3种Mock测试方案

前端性能测试怎么做?

如果你想玩转 Dubbo 接口测试?一定要知道这 3 种姿势

测试人员如何快速熟悉新业务?

可用性保障平台的自动化测试探索与实践

如何测试 Redis 缓存?

如何保障需求质量(下):你应该做到的

如何保障需求质量(上):你应该知道的

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

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存