# SQLTune **Repository Path**: elfbobo_admin_admin/sqltune ## Basic Information - **Project Name**: SQLTune - **Description**: SQLTune 是一个强大的 SQL 语句转换工具,核心优势是提供 Spring Boot 零侵入集成方案,能够将一种数据库方言的 SQL 语句无缝转换为另一种数据库方言的 SQL 语句(例如将 Oracle SQL 转换为 MySQL SQL),实现跨数据库的 SQL 兼容性。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2025-12-08 - **Last Updated**: 2025-12-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SQLTune (ST) SQLTune 是一个强大的 SQL 语句转换工具,**核心优势是提供 Spring Boot 零侵入集成方案**,能够将一种数据库方言的 SQL 语句无缝转换为另一种数据库方言的 SQL 语句(例如将 Oracle SQL 转换为 MySQL SQL),实现跨数据库的 SQL 兼容性。 ## 技术架构与先进性 ### 🛠️ 核心技术 - **双引擎解析与转换**: - **基于 ANTLR4 的语法树 (AST) 转换**:使用 ANTLR4 构建精确的 SQL 解析器,将 SQL 解析为抽象语法树,实现高精度的语义级转换 - **基于 Apache Calcite 的高级 SQL 处理**:集成 Apache Calcite 作为高级 SQL 解析、优化和转换框架,提供更强大的 SQL 语义理解和优化能力 - **Spring Boot 零侵入集成**:通过自定义 JDBC 驱动或数据源代理方式,实现对 Spring Boot 项目的无缝集成 - **插件化架构**:支持动态加载和扩展转换规则,可通过 JAR 文件或类路径加载自定义插件 - **分层设计**:采用 API 层、核心层、扩展层、基础层的分层架构,提供良好的扩展性和可维护性 ### 🚀 技术先进性 - **零侵入集成**:无需修改原有 SQL 代码,只需添加依赖和配置即可实现 SQL 自动转换 - **高精度转换**:基于语法树的转换方式能够准确理解 SQL 语义,避免简单字符串替换的局限性 - **灵活扩展**:提供丰富的扩展点,支持自定义转换规则和数据库方言 - **高性能**:转换过程在内存中完成,性能开销极小 - **广泛兼容性**:支持多种数据库方言之间的转换,包括 Oracle、MySQL、PostgreSQL 等 ## 快速开始 ### 🎯 Spring Boot 零侵入集成(推荐核心用法) **只需 3 步,无需修改原有 SQL 代码,即可实现 SQL 自动转换:** #### 1. 添加依赖 在 Spring Boot 项目的 `pom.xml` 中添加依赖: ```xml com.sqltune sqltune-spring-boot-starter 1.0.0-SNAPSHOT ``` #### 2. 配置文件 在 `application.properties` 或 `application.yml` 中添加配置: ```properties # SQLTune 核心配置 - 仅需几行配置即可启用 # 源数据库方言(如:oracle) sqltune.source-dialect=oracle # 目标数据库方言(如:mysql) sqltune.target-dialect=mysql # 启用 JDBC 自动拦截 - 关键配置,实现零代码修改 # 开启后,所有通过 JDBC 执行的 SQL 都会被自动转换 sqltune.enable-jdbc-intercept=true # SQL优化器类型:basic(基础优化器)或calcite(基于Calcite的高级优化器) sqltune.optimizer-type=calcite ``` #### 3. 使用原有代码,自动生效 无需修改任何原有 SQL 代码,所有通过 JDBC 执行的 SQL 都会被自动转换: ```java @Service public class UserService { private final JdbcTemplate jdbcTemplate; @Autowired public UserService(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public List getActiveUsers() { // ✅ 写 Oracle SQL String oracleSql = "SELECT * FROM users WHERE status = 'ACTIVE' AND ROWNUM <= 10"; // ✅ 无需修改代码,SQL 会被自动转换为 MySQL // 转换后: SELECT * FROM users WHERE status = 'ACTIVE' LIMIT 10 return jdbcTemplate.query(oracleSql, (rs, rowNum) -> { // ... 原有代码 }); } } ``` --- ### 🔄 现有项目零开发数据库切换方案 **对于已经上线或开发完成的项目,无需修改任何代码,即可实现数据库的丝滑切换:** SQLTune 支持两种实现方式,您可以根据需求选择合适的模式: #### 方式一:数据源代理模式(推荐,无需修改代码) 当`sqltune.enable-jdbc-intercept=true`时,SQLTune 会自动代理所有数据源,无需修改 URL 和驱动类: 1. **添加依赖**:在现有项目的 `pom.xml` 中添加 SQLTune Spring Boot Starter 依赖 2. **修改配置**: ```properties # 1. 修改数据库连接(使用标准MySQL驱动,无需sqltune前缀) spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 2. 添加 SQLTune 配置 # 源数据库方言:oracle(原有数据库) sqltune.source-dialect=oracle # 目标数据库方言:mysql(新数据库) sqltune.target-dialect=mysql # 启用JDBC自动拦截 - 关键配置,实现零代码修改 sqltune.enable-jdbc-intercept=true # SQL优化器类型:basic(基础优化器)或calcite(基于Calcite的高级优化器) sqltune.optimizer-type=calcite ``` 3. **启动项目**:无需修改任何业务代码,项目即可正常运行 #### 方式二:自定义 JDBC 驱动模式 使用 SQLTune 自定义 JDBC 驱动来拦截并自动转换 SQL 语句: 1. **添加依赖**:在现有项目的 `pom.xml` 中添加 SQLTune Spring Boot Starter 依赖 2. **修改配置**: ```properties # 1. 修改数据库连接(使用SQLTune驱动) spring.datasource.url=jdbc:sqltune:jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=password spring.datasource.driver-class-name=com.sqltune.spring.boot.starter.jdbc.SqlTuneDriver # 2. 添加 SQLTune 配置 # 源数据库方言:oracle(原有数据库) sqltune.source-dialect=oracle # 目标数据库方言:mysql(新数据库) sqltune.target-dialect=mysql # 启用自动转换 sqltune.enable-jdbc-intercept=true # SQL优化器类型:basic(基础优化器)或calcite(基于Calcite的高级优化器) sqltune.optimizer-type=calcite ``` 3. **启动项目**:无需修改任何业务代码,项目即可正常运行 **两种方式的区别:** - 数据源代理模式:配置更简单,类似 ShardingJDBC,无需修改 URL 和驱动类 - 自定义 JDBC 驱动模式:需要修改 URL 和驱动类,但更直接控制 JDBC 连接 **切换效果**: - 原有 Oracle 风格的 SQL(如 `SELECT * FROM users WHERE ROWNUM <= 10`) - 自动转换为 MySQL 风格的 SQL(如 `SELECT * FROM users LIMIT 10`) - 所有数据库操作完全兼容 #### 支持的切换场景 | 源数据库 | 目标数据库 | 支持程度 | | ---------- | ---------- | ----------- | | Oracle | MySQL | ✅ 完全支持 | | Oracle | PostgreSQL | ✅ 完全支持 | | MySQL | PostgreSQL | ✅ 完全支持 | | PostgreSQL | MySQL | ✅ 完全支持 | | 更多组合 | ... | ✅ 持续扩展 | **优势**: - 零开发成本:无需修改任何业务代码 - 零风险:保留原有 SQL 逻辑,避免引入新的 Bug - 零学习成本:无需了解目标数据库的 SQL 语法差异 - 快速切换:从准备到完成仅需几分钟 - 可回滚:随时可以切换回原数据库 ## 环境要求与安装 ### 环境要求 - JDK 1.8+ - Maven 3.5+ - Spring Boot 2.0+(使用 Spring Boot 集成时) - Apache Calcite 1.34.0+(自动通过 Maven 依赖管理) ### 项目安装(可选,仅需本地开发时) 1. 克隆项目: ```bash git clone https://gitee.com/finpire/sqltune.git cd sqltune ``` 2. 编译项目: ```bash mvn clean install -DskipTests ``` ## 其他使用方式 除了 Spring Boot 零侵入集成外,SQLTune 还提供以下使用方式: ### 1. 完整 Spring Boot 配置(高级功能) 如果需要使用更多高级功能,可以参考以下完整配置: ```properties # SQLTune 完整配置 # 源数据库方言(支持:oracle、mysql、mariadb、dm、kingbase、postgresql、sqlserver) sqltune.source-dialect=oracle # 目标数据库方言(支持:oracle、mysql、mariadb、dm、kingbase、postgresql、sqlserver) sqltune.target-dialect=mysql # 是否启用日志(默认:false) sqltune.enable-log=false # 是否启用SQL优化(默认:true) sqltune.enable-optimization=true # SQL优化器类型:basic(基础优化器)或calcite(基于Calcite的高级优化器) sqltune.optimizer-type=calcite # 是否启用JDBC自动拦截(默认:false) sqltune.enable-jdbc-intercept=true # 序列转换策略:仅在源数据库支持序列(如Oracle、PostgreSQL)且目标数据库为MySQL时生效 # 可选值:AUTO_INCREMENT(使用MySQL自增ID)、NEXTVAL(使用自定义nextval函数) sqltune.sequence-strategy=AUTO_INCREMENT # 默认值为AUTO_INCREMENT ``` 或使用 YAML 格式: ```yaml sqltune: # 源数据库方言(支持:oracle、mysql、mariadb、dm、kingbase、postgresql、sqlserver) source-dialect: oracle # 目标数据库方言(支持:oracle、mysql、mariadb、dm、kingbase、postgresql、sqlserver) target-dialect: mysql enable-log: false enable-optimization: true # SQL优化器类型:basic(基础优化器)或calcite(基于Calcite的高级优化器) optimizer-type: calcite enable-jdbc-intercept: true # 序列转换策略:仅在源数据库支持序列(如Oracle、PostgreSQL)且目标数据库为MySQL时生效 # 可选值:AUTO_INCREMENT(使用MySQL自增ID)、NEXTVAL(使用自定义nextval函数) sequence-strategy: AUTO_INCREMENT # 默认值为AUTO_INCREMENT ``` ### 2. 配置文件方式 创建配置文件 `sqltune.yaml`: ```yaml rules: sql-rewrite: source-database: oracle target-database: mysql optimizer-type: calcite # SQL优化器类型:basic(基础优化器)或calcite(基于Calcite的高级优化器) ``` 使用 SQLTune 转换 SQL: ```java import com.sqltune.core.SqlTuneEngine; import com.sqltune.core.SqlTuneResult; public class Example { public static void main(String[] args) { // 创建SQLTune引擎 SqlTuneEngine engine = SqlTuneEngine.builder() .configFile("sqltune.yaml") .build(); // Oracle SQL语句 String oracleSql = "SELECT * FROM users WHERE status = 'ACTIVE' AND ROWNUM <= 10"; // 转换为MySQL SQL SqlTuneResult result = engine.rewrite(oracleSql); // 输出转换后的SQL System.out.println("Original SQL: " + oracleSql); System.out.println("Rewritten SQL: " + result.getRewrittenSql()); // 输出: SELECT * FROM users WHERE status = 'ACTIVE' LIMIT 10 } } ``` ### 3. 编程方式配置 ```java import com.sqltune.core.SqlTuneEngine; import com.sqltune.core.SqlTuneResult; import com.sqltune.config.SqlTuneConfig; public class Example { public static void main(String[] args) { // 创建配置 SqlTuneConfig config = SqlTuneConfig.builder() .sourceDatabase("oracle") .targetDatabase("mysql") .optimizerType("calcite") // 设置优化器类型:basic(基础优化器)或calcite(基于Calcite的高级优化器) .build(); // 创建SQLTune引擎 SqlTuneEngine engine = SqlTuneEngine.builder() .config(config) .build(); // Oracle SQL语句示例 String[] oracleSqls = { "SELECT * FROM users WHERE status = 'ACTIVE' AND ROWNUM <= 10", "SELECT id, NVL(name, 'Unknown') AS name FROM users", "SELECT * FROM orders WHERE TO_CHAR(order_date, 'YYYY-MM-DD') = '2023-01-01'" }; // 转换为MySQL SQL for (String sql : oracleSqls) { SqlTuneResult result = engine.rewrite(sql); System.out.println("Original SQL: " + sql); System.out.println("Rewritten SQL: " + result.getRewrittenSql()); System.out.println(); } } } ``` ### 4. 输出结果示例 ``` Original SQL: SELECT * FROM users WHERE status = 'ACTIVE' AND ROWNUM <= 10 Rewritten SQL: SELECT * FROM users WHERE status = 'ACTIVE' LIMIT 10 Original SQL: SELECT id, NVL(name, 'Unknown') AS name FROM users Rewritten SQL: SELECT id, COALESCE(name, 'Unknown') AS name FROM users Original SQL: SELECT * FROM orders WHERE TO_CHAR(order_date, 'YYYY-MM-DD') = '2023-01-01' Rewritten SQL: SELECT * FROM orders WHERE DATE_FORMAT(order_date, '%Y-%m-%d') = '2023-01-01' ``` ### 5. Apache Calcite 优化示例 ``` # 原始复杂SQL SELECT o.id, o.customer_id, SUM(oi.quantity * oi.price) AS total_amount FROM orders o JOIN order_items oi ON o.id = oi.order_id JOIN products p ON oi.product_id = p.id WHERE o.status = 'COMPLETED' AND p.category = 'ELECTRONICS' GROUP BY o.id, o.customer_id HAVING SUM(oi.quantity * oi.price) > 1000 ORDER BY total_amount DESC LIMIT 10 # Calcite优化后的SQL SELECT o.id, o.customer_id, SUM(oi.quantity * oi.price) AS total_amount FROM orders o JOIN ( SELECT order_id, quantity, price FROM order_items WHERE product_id IN ( SELECT id FROM products WHERE category = 'ELECTRONICS' ) ) oi ON o.id = oi.order_id WHERE o.status = 'COMPLETED' GROUP BY o.id, o.customer_id HAVING SUM(oi.quantity * oi.price) > 1000 ORDER BY total_amount DESC LIMIT 10 ``` ## 功能特性 ### 🌟 核心价值 - **零代码修改**:无需修改原有 SQL 代码,只需添加依赖和配置即可实现 SQL 自动转换 - **快速集成**:Spring Boot 项目只需添加一个依赖并配置几行属性,即可立即启用 - **跨库兼容**:解决不同数据库方言差异,实现一套代码适配多种数据库 - **现成项目 0 开发切换**:对于已有的项目,无需任何开发工作,即可丝滑切换到其他数据库 - **降低迁移成本**:大幅减少数据库迁移时的 SQL 改写工作量,缩短迁移周期 ### 🚀 主要功能 - **Spring Boot 无缝集成**:提供 Spring Boot Starter,一行依赖即可集成 - **JDBC 自动拦截**:自动拦截所有 JDBC SQL 执行,无需显式调用转换方法 - **SQL 方言转换**:支持多种数据库方言之间的 SQL 转换(如 Oracle → MySQL、MySQL → PostgreSQL 等) - **智能函数映射**:自动将源数据库函数映射到目标数据库对应的函数(如 Oracle NVL → MySQL COALESCE) - **行限制转换**:支持将 Oracle ROWNUM 转换为 MySQL LIMIT 等行限制语法 - **配置灵活**:支持通过配置文件或编程方式自定义转换规则 - **支持复杂 SQL**:能够处理复杂的 SELECT、INSERT、UPDATE、DELETE 语句,包括子查询、连接查询等 - **SQL 优化器**:可选功能,支持对 SQL 语句进行优化处理,提高执行效率 - **健壮的错误处理**:完善的异常捕获机制,确保转换过程的稳定性 - **分层架构**:采用分层设计,具有良好的扩展性和可维护性 ## 架构设计 SQLTune 采用分层架构设计: 1. **API 层**:提供对外接口,包括 SQL 转换服务、配置管理等 2. **核心层**:包含 SQL 解析、改写、优化等核心功能 3. **扩展层**:提供各种数据库方言的支持和自定义规则的扩展点 4. **基础层**:包含工具类、通用组件等基础功能 | 层级 | 功能描述 | | ------ | ------------------------------------------------------------------------------------------------------- | | API 层 | - SQL 转换服务接口
- 配置管理接口 | | 核心层 | - SQL 解析器 (Parser)
- SQL 改写器 (Rewriter)
- SQL 优化器 (Optimizer)
- SQL 执行器 (Executor) | | 扩展层 | - Oracle 方言支持
- MySQL 方言支持
- PostgreSQL 方言支持
- 自定义规则扩展点 | | 基础层 | - 工具类
- 通用组件
- 异常处理 | ## 支持的数据库 当前支持的数据库方言: - Oracle - MySQL - MariaDB - 达梦(DM) - PostgreSQL - 人大金仓(KINGBASE) - SQL Server ### 支持的转换对 根据数据库的语法相似性,SQLTune 支持以下转换对: 1. **Oracle <-> MySQL/MariaDB/PostgreSQL/KINGBASE** 2. **DM <-> MySQL/MariaDB/PostgreSQL/KINGBASE** 3. **MySQL <-> MariaDB** 4. **MySQL <-> PostgreSQL/KINGBASE** 5. **MariaDB <-> PostgreSQL/KINGBASE** 6. **PostgreSQL <-> KINGBASE** **注意**:SQL Server 仅作为源数据库支持部分转换,当前不支持作为目标数据库的全面转换。 ## 项目结构 ``` sqltune/ ├── sqltune-api/ # API 层 ├── sqltune-core/ # 核心层 │ └── src/main/antlr4/ # ANTLR4 语法文件目录 ├── sqltune-extension/ # 扩展层 ├── sqltune-common/ # 基础层 ├── sqltune-examples/ # 示例代码 ├── sqltune-spring-boot-starter/ # Spring Boot Starter 模块 └── pom.xml # Maven 父工程配置 ``` **注意**:sqltune 目录中包含.gitignore 和 LICENSE 文件,是一个独立的 git 仓库。 ## 核心组件 ### 核心组件 #### SQL 解析器 (Parser) 负责将 SQL 语句解析为抽象语法树(AST),支持多种数据库方言的解析。 解析器基于 ANTLR4 实现,语法文件位于 `sqltune-core/src/main/antlr4/` 目录,包含以下数据库的语法定义: - MySQL - MariaDB - PostgreSQL - Oracle (PL/SQL) - SQL Server (TSQL) #### SQL 改写器 (Rewriter) 根据目标数据库方言的规则,对抽象语法树进行改写,实现 SQL 方言的转换。 #### SQL 优化器 提供双重 SQL 优化能力: **基础优化器**: - 移除多余空格和换行 - 移除不必要的括号 - 优化 WHERE 子句条件 - 优化 ORDER BY 子句 - 移除不必要的 DISTINCT **基于 Apache Calcite 的高级优化器**: - 基于成本的查询优化(CBO) - 关系代数优化(如谓词下推、投影下推) - 连接顺序优化 - 子查询优化 - 窗口函数优化 - 物化视图支持 - 多表连接优化 #### SQL 执行器 可选组件,用于执行转换后的 SQL 语句。 #### 自定义 JDBC 驱动 提供自定义 JDBC 驱动,实现 SQL 语句的自动转换,无需修改原有代码即可实现跨数据库兼容。 ## 扩展开发 SQLTune 提供了丰富的扩展点,允许用户自定义转换规则: 1. **自定义改写规则**:实现`SqlRewriteRule`接口 2. **自定义数据库方言**:继承`AbstractDatabaseDialect`类 3. **自定义解析器**:实现`SqlParser`接口 ### 插件化架构 SQLTune 支持插件化架构,允许用户动态加载和扩展功能。插件机制提供了一种灵活的方式来扩展 SQLTune 的能力,无需修改核心代码。 #### 插件开发 要开发一个 SQLTune 插件,需要: 1. **创建插件类**:实现`Plugin`接口或继承`AbstractPlugin`类 2. **注册扩展点**:在插件的`doInitialize()`方法中注册自定义组件 **示例插件**: ```java package com.sqltune.example.plugin; import com.sqltune.core.plugin.AbstractPlugin; import com.sqltune.core.rewrite.SqlRewriteRule; import com.sqltune.core.rewrite.context.RewriteContext; import com.sqltune.core.parser.SqlParser; import com.sqltune.core.dialect.AbstractDatabaseDialect; import com.sqltune.core.registry.RewriteRuleRegistry; import com.sqltune.core.registry.ParserRegistry; import com.sqltune.core.registry.DialectRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ExamplePlugin extends AbstractPlugin { private static final Logger LOGGER = LoggerFactory.getLogger(ExamplePlugin.class); public ExamplePlugin() { super("ExamplePlugin", "1.0.0", "示例插件,演示插件化架构的使用"); } @Override protected void doInitialize() { LOGGER.info("ExamplePlugin 正在初始化..."); // 1. 注册自定义SQL改写规则 RewriteRuleRegistry.getInstance().registerRule(new CustomRewriteRule()); // 2. 注册自定义数据库方言 DialectRegistry.getInstance().registerDialect("CUSTOM_DB", new CustomDatabaseDialect()); // 3. 注册自定义SQL解析器 ParserRegistry.getInstance().registerParser("CUSTOM_DB", new CustomSqlParser()); LOGGER.info("ExamplePlugin 初始化完成"); } @Override protected void doStart() { LOGGER.info("ExamplePlugin 正在启动..."); // 可以在这里执行插件启动时需要的操作 LOGGER.info("ExamplePlugin 启动完成"); } @Override protected void doStop() { LOGGER.info("ExamplePlugin 正在停止..."); // 可以在这里执行插件停止时需要的操作 LOGGER.info("ExamplePlugin 停止完成"); } @Override protected void doDestroy() { LOGGER.info("ExamplePlugin 正在销毁..."); // 可以在这里执行插件销毁时需要的操作 LOGGER.info("ExamplePlugin 销毁完成"); } // 示例:自定义SQL改写规则实现 private static class CustomRewriteRule implements SqlRewriteRule { @Override public boolean matches(RewriteContext context) { // 定义规则匹配条件,例如:匹配包含特定函数的SQL return context.getOriginalSql().contains("CUSTOM_FUNCTION"); } @Override public String rewrite(RewriteContext context) { // 实现自定义改写逻辑 String originalSql = context.getOriginalSql(); return originalSql.replace("CUSTOM_FUNCTION", "STANDARD_FUNCTION"); } } // 示例:自定义数据库方言实现 private static class CustomDatabaseDialect extends AbstractDatabaseDialect { @Override public String getDialectName() { return "CUSTOM_DB"; } @Override public String getDriverClassName() { return "com.custom.db.Driver"; } // 实现其他方言特定方法... } // 示例:自定义SQL解析器实现 private static class CustomSqlParser implements SqlParser { @Override public String getSupportedDialect() { return "CUSTOM_DB"; } @Override public Object parse(String sql) { // 实现自定义SQL解析逻辑 // 实际使用中通常基于ANTLR4实现 return new Object(); // 返回抽象语法树(AST) } } } ``` #### 插件加载 SQLTune 支持从 JAR 文件或类路径加载插件: **从 JAR 文件加载插件**: ```java PluginManager pluginManager = PluginManager.getInstance(); pluginManager.loadPluginFromJar("/path/to/my-plugin.jar"); ``` **从类路径加载插件**: ```java PluginManager pluginManager = PluginManager.getInstance(); pluginManager.loadPluginFromClasspath("com.sqltune.example.plugin.ExamplePlugin"); ``` #### 插件 JAR 结构 插件 JAR 文件需要包含一个`META-INF/plugin.properties`文件,指定插件类名: ```properties plugin.class=com.sqltune.example.plugin.ExamplePlugin ``` ## SQL 转换技术研究 ### 1. SQL 转换技术分类 根据当前研究和实践,数据库 SQL 转换技术主要分为以下几类: #### 1.1 字符串替换式转换 - **原理**:基于正则表达式或字符串匹配进行简单的关键字替换 - **代表工具**:早期的数据库迁移工具 - **特点**:实现简单,但准确性低,无法处理复杂 SQL #### 1.2 语法树(AST)转换 - **原理**:将 SQL 解析为抽象语法树,然后根据目标数据库规则进行语义级转换 - **代表工具**:SQLTune、CrackSQL 等 - **特点**:转换准确性高,能够处理复杂 SQL 结构 #### 1.3 语义规则映射转换 - **原理**:基于预定义的语义规则映射表进行转换 - **代表工具**:部分商业数据库迁移工具 - **特点**:规则明确,易于扩展,但规则维护成本高 #### 1.4 机器学习辅助转换 - **原理**:利用机器学习模型学习不同数据库 SQL 的转换模式 - **代表技术**:NL2SQL 技术的扩展应用 - **特点**:能够处理未见过的转换场景,但需要大量训练数据 ### 2. 相关研究与文献 #### 2.1 学术研究 - **CrackSQL**:首个高效、准确的 SQL 方言翻译系统,采用基于 AST 的转换方法,为数据库迁移和跨数据库分析提供支持 - **NL2SQL 技术**:将自然语言查询转换为 SQL 查询的技术,提高数据库查询的友好性和效率,部分研究已扩展到跨数据库 SQL 转换领域 #### 2.2 工业实践 - **分布式数据库迁移方法**:工业界提出的数据库迁移最佳实践,强调通过自动化工具降低迁移难度和风险 - **数据库厂商迁移工具**:各数据库厂商提供的专有迁移工具,如 Oracle SQL Developer、MySQL Workbench 等,支持特定数据库间的转换 ### 3. SQL 转换技术比较 | 转换技术 | 准确性 | 复杂 SQL 支持 | 扩展性 | 性能 | 实现难度 | | ---------------- | ------ | ------------- | ------ | ---- | -------- | | 字符串替换式转换 | 低 | 弱 | 中 | 高 | 低 | | 语法树(AST)转换 | 高 | 强 | 高 | 中 | 高 | | 语义规则映射转换 | 中 | 中 | 中 | 中 | 中 | | 机器学习辅助转换 | 中高 | 中 | 高 | 低 | 高 | ### 4. SQLTune 的转换方式分析 SQLTune 采用的是**基于语法树(AST)的静态转换方式**,具体实现流程如下: 1. **SQL 解析**:使用 ANTLR4 将源数据库 SQL 解析为抽象语法树(AST) 2. **AST 改写**:根据目标数据库方言规则,对 AST 进行节点级别的改写 3. **SQL 生成**:将改写后的 AST 重新生成为目标数据库的 SQL 语句 ### 5. 优缺点评估 #### 优点: | 优势 | 描述 | | ---------------- | --------------------------------------------------------------------- | | **零侵入集成** | Spring Boot 项目无需修改任何 SQL 代码即可实现自动转换 | | **高精度转换** | 基于语法树的转换方式能够准确理解 SQL 语义,避免简单字符串替换的局限性 | | **灵活扩展** | 提供丰富的扩展点,支持自定义转换规则和数据库方言 | | **支持复杂 SQL** | 能够处理包含子查询、连接查询等复杂 SQL 语句的转换 | | **高性能** | 转换过程在内存中完成,性能开销极小 | #### 缺点: | 局限 | 描述 | | -------------------- | ------------------------------------------------------------- | | **依赖语法定义** | 需要为每种支持的数据库提供完整的 ANTLR4 语法定义 | | **复杂函数支持有限** | 对于某些数据库特有的复杂函数,转换支持可能不够完善 | | **存储过程支持有限** | 目前主要支持 SQL 查询语句转换,复杂存储过程的转换能力有待提升 | | **版本兼容性挑战** | 不同数据库版本的语法差异可能影响转换准确性 | ## 调试技巧 SQLTune 内置了详细的调试信息,可以帮助开发人员定位和解决转换问题: ```java // 启用调试日志(通过日志配置或代码) System.setProperty("logging.level.com.sqltune", "DEBUG"); // 或者使用编程方式检查类加载情况 Class rewriterClass = Class.forName("com.sqltune.extension.rewriter.GenericSqlRewriter"); System.out.println("Rewriter class: " + rewriterClass.getName()); System.out.println("Rewriter class loader: " + rewriterClass.getClassLoader()); System.out.println("Rewriter class location: " + rewriterClass.getProtectionDomain().getCodeSource().getLocation()); ``` 除了 Spring Boot 零侵入集成外,SQLTune 还提供以下使用方式: ### 1. 完整 Spring Boot 配置(高级功能) 如果需要使用更多高级功能,可以参考以下完整配置: ```properties # SQLTune 完整配置 # 源数据库方言(支持:oracle、mysql、mariadb、dm、kingbase、postgresql、sqlserver) sqltune.source-dialect=oracle # 目标数据库方言(支持:oracle、mysql、mariadb、dm、kingbase、postgresql、sqlserver) sqltune.target-dialect=mysql # 是否启用日志(默认:false) sqltune.enable-log=false # 是否启用SQL优化(默认:true) sqltune.enable-optimization=true # 是否启用JDBC自动拦截(默认:false) sqltune.enable-jdbc-intercept=true # 序列转换策略:仅在源数据库支持序列(如Oracle、PostgreSQL)且目标数据库为MySQL时生效 # 可选值:AUTO_INCREMENT(使用MySQL自增ID)、NEXTVAL(使用自定义nextval函数) sqltune.sequence-strategy=AUTO_INCREMENT # 默认值为AUTO_INCREMENT ``` 或使用 YAML 格式: ```yaml sqltune: # 源数据库方言(支持:oracle、mysql、mariadb、dm、kingbase、postgresql、sqlserver) source-dialect: oracle # 目标数据库方言(支持:oracle、mysql、mariadb、dm、kingbase、postgresql、sqlserver) target-dialect: mysql enable-log: false enable-optimization: true enable-jdbc-intercept: true # 序列转换策略:仅在源数据库支持序列(如Oracle、PostgreSQL)且目标数据库为MySQL时生效 # 可选值:AUTO_INCREMENT(使用MySQL自增ID)、NEXTVAL(使用自定义nextval函数) sequence-strategy: AUTO_INCREMENT # 默认值为AUTO_INCREMENT ``` ### 2. 配置文件方式 创建配置文件 `sqltune.yaml`: ```yaml rules: sql-rewrite: source-database: oracle target-database: mysql ``` 使用 SQLTune 转换 SQL: ```java import com.sqltune.core.SqlTuneEngine; import com.sqltune.core.SqlTuneResult; public class Example { public static void main(String[] args) { // 创建SQLTune引擎 SqlTuneEngine engine = SqlTuneEngine.builder() .configFile("sqltune.yaml") .build(); // Oracle SQL语句 String oracleSql = "SELECT * FROM users WHERE status = 'ACTIVE' AND ROWNUM <= 10"; // 转换为MySQL SQL SqlTuneResult result = engine.rewrite(oracleSql); // 输出转换后的SQL System.out.println("Original SQL: " + oracleSql); System.out.println("Rewritten SQL: " + result.getRewrittenSql()); // 输出: SELECT * FROM users WHERE status = 'ACTIVE' LIMIT 10 } } ``` ### 3. 编程方式配置 ```java import com.sqltune.core.SqlTuneEngine; import com.sqltune.core.SqlTuneResult; import com.sqltune.config.SqlTuneConfig; public class Example { public static void main(String[] args) { // 创建配置 SqlTuneConfig config = SqlTuneConfig.builder() .sourceDatabase("oracle") .targetDatabase("mysql") .build(); // 创建SQLTune引擎 SqlTuneEngine engine = SqlTuneEngine.builder() .config(config) .build(); // Oracle SQL语句示例 String[] oracleSqls = { "SELECT * FROM users WHERE status = 'ACTIVE' AND ROWNUM <= 10", "SELECT id, NVL(name, 'Unknown') AS name FROM users", "SELECT * FROM orders WHERE TO_CHAR(order_date, 'YYYY-MM-DD') = '2023-01-01'" }; // 转换为MySQL SQL for (String sql : oracleSqls) { SqlTuneResult result = engine.rewrite(sql); System.out.println("Original SQL: " + sql); System.out.println("Rewritten SQL: " + result.getRewrittenSql()); System.out.println(); } } } ``` ### 4. 输出结果示例 ``` Original SQL: SELECT * FROM users WHERE status = 'ACTIVE' AND ROWNUM <= 10 Rewritten SQL: SELECT * FROM users WHERE status = 'ACTIVE' LIMIT 10 Original SQL: SELECT id, NVL(name, 'Unknown') AS name FROM users Rewritten SQL: SELECT id, COALESCE(name, 'Unknown') AS name FROM users Original SQL: SELECT * FROM orders WHERE TO_CHAR(order_date, 'YYYY-MM-DD') = '2023-01-01' Rewritten SQL: SELECT * FROM orders WHERE DATE_FORMAT(order_date, '%Y-%m-%d') = '2023-01-01' ``` ## 环境要求与安装 ### 环境要求 - JDK 1.8+ - Maven 3.5+ - Spring Boot 2.0+(使用 Spring Boot 集成时) ### 项目安装(可选,仅需本地开发时) 1. 克隆项目: ```bash git clone https://gitee.com/finpire/sqltune.git cd sqltune ``` 2. 编译项目: ```bash mvn clean install -DskipTests ``` ## 贡献 欢迎提交 Issue 和 Pull Request! ## 许可证 SQLTune 采用 Apache License 2.0 许可证。 ## 联系方式 如有问题或建议,请通过以下方式联系: - Email: 602349518@qq.com - GitHub Issues: https://gitee.com/finpire/sqltune/issues