基于 JSqlParser 搭建一套完整的 SQL 分析与改写引擎,核心是要掌握从SQL 解析到AST 操作再到SQL 生成的全流程,并能将其封装成可复用的引擎组件,适配各类业务场景(如合规校验、自动改写、权限控制等)。
下面我会带你从零构建一个结构化的 SQL 分析与改写引擎,包含核心架构设计、关键功能实现和完整示例代码,你可以直接基于这个框架扩展到自己的业务场景中。
一、引擎整体架构设计
一个通用的 SQL 分析与改写引擎需要具备以下核心模块,各模块职责清晰、可插拔:
A[SQL输入] --> B[SQL解析模块] B --> C[AST校验模块] C --> D{校验结果} D -->|通过| E[AST改写模块] D -->|不通过| F[异常提示] E --> G[SQL生成模块] G --> H[改写后SQL输出]- SQL 解析模块:将原始 SQL 字符串解析为 AST(抽象语法树),处理解析异常;
- AST 校验模块:遍历 AST 检查 SQL 合规性、风险点(如无 WHERe 的 DELETe、SELECT * 等);
- AST 改写模块:根据业务规则修改 AST(如追加权限条件、添加 LIMIT、替换表名等);
- SQL 生成模块:将修改后的 AST 重新生成为合法的 SQL 字符串。
二、环境准备
首先需要引入 JSqlParser 依赖(Maven 为例):
<dependency> <groupId>net.sf.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>4.9</version> <!-- 推荐使用稳定版,最新版可查Maven仓库 --></dependency>三、核心引擎实现
下面是完整的 SQL 分析与改写引擎代码,封装为可复用的工具类,包含解析、校验、改写三大核心功能:
1. 核心引擎类(SqlRewriteEngine)
import net.sf.jsqlparser.JSQLParserException;import net.sf.jsqlparser.expression.expression;import net.sf.jsqlparser.expression.LongValue;import net.sf.jsqlparser.expression.operators.conditional.Andexpression;import net.sf.jsqlparser.parser.CCJSqlParserUtil;import net.sf.jsqlparser.statement.Statement;import net.sf.jsqlparser.statement.delete.Delete;import net.sf.jsqlparser.statement.select.Limit;import net.sf.jsqlparser.statement.select.PlainSelect;import net.sf.jsqlparser.statement.select.Select;public class SqlRewriteEngine { // -------------------------- 核心解析方法 -------------------------- public Statement parseSql(String sql) throws JSQLParserException { if (sql == null || sql.trim().isEmpty()) { throw new IllegalArgumentException("SQL字符串不能为空"); } return CCJSqlParserUtil.parse(sql); } // -------------------------- 校验模块 -------------------------- public boolean checkDeleteHasWhere(Statement statement) { if (statement instanceof Delete) { Delete delete = (Delete) statement; return delete.getWhere() != null; } // 非DELETE语句默认合规 return true; } public boolean checkSelectNoStar(Statement statement) { if (statement instanceof Select) { Select select = (Select) statement; if (select.getSelectBody() instanceof PlainSelect) { PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); // 检查SELECT子句是否包含"*" return !plainSelect.getSelectItems().stream() .anyMatch(item -> item.toString().equals("*")); } } return true; } // -------------------------- 改写模块 -------------------------- public Statement addLimitToSelect(Statement statement, int limitNum) { if (statement instanceof Select) { Select select = (Select) statement; if (select.getSelectBody() instanceof PlainSelect) { PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); // 仅当无LIMIT时添加 if (plainSelect.getLimit() == null) { Limit limit = new Limit(); limit.setRowCount(new LongValue(limitNum)); plainSelect.setLimit(limit); } } } return statement; } public Statement addPermissionCondition(Statement statement, String permissionCondition) throws JSQLParserException { expression conditionExpr = CCJSqlParserUtil.parseCondexpression(permissionCondition); // 处理SELECT语句 if (statement instanceof Select) { Select select = (Select) statement; if (select.getSelectBody() instanceof PlainSelect) { PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); expression oldWhere = plainSelect.getWhere(); // 拼接AND条件:原有WHERe + AND + 权限条件 plainSelect.setWhere(oldWhere == null ? conditionExpr : new Andexpression(oldWhere, conditionExpr)); } } // 处理DELETE语句(同理可扩展UPDATE/INSERT) else if (statement instanceof Delete) { Delete delete = (Delete) statement; expression oldWhere = delete.getWhere(); delete.setWhere(oldWhere == null ? conditionExpr : new Andexpression(oldWhere, conditionExpr)); } return statement; } // -------------------------- 生成模块 -------------------------- public String generateSql(Statement statement) { return statement.toString(); } // -------------------------- 一站式方法(简化调用) -------------------------- public String processSql(String originalSql, int limitNum, String permissionCondition) throws JSQLParserException { // 1. 解析SQL Statement statement = parseSql(originalSql); // 2. 校验SQL(校验失败可抛出异常) if (!checkDeleteHasWhere(statement)) { throw new IllegalArgumentException("DELETE语句必须包含WHERe条件"); } if (!checkSelectNoStar(statement)) { throw new IllegalArgumentException("SELECT语句禁止使用SELECT *"); } // 3. 改写SQL statement = addLimitToSelect(statement, limitNum); if (permissionCondition != null && !permissionCondition.trim().isEmpty()) { statement = addPermissionCondition(statement, permissionCondition); } // 4. 生成最终SQL return generateSql(statement); }}2. 引擎使用示例
public class SqlRewriteEngineDemo { public static void main(String[] args) { SqlRewriteEngine engine = new SqlRewriteEngine(); // 示例1:处理SELECT语句(添加LIMIT + 行级权限) try { String originalSelectSql = "SELECT id, name FROM user WHERe age > 18"; // 改写:添加LIMIT 1000 + 追加部门条件dept_id = '001' String processedSql = engine.processSql(originalSelectSql, 1000, "dept_id = '001'"); System.out.println("原始SELECT SQL:" + originalSelectSql); System.out.println("改写后SELECT SQL:" + processedSql); // 输出:SELECT id, name FROM user WHERe age > 18 AND dept_id = '001' LIMIT 1000 } catch (Exception e) { e.printStackTrace(); } // 示例2:处理DELETe语句(校验WHERe + 追加权限) try { String originalDeleteSql = "DELETE FROM user WHERe id = 123"; String processedSql = engine.processSql(originalDeleteSql, 0, "dept_id = '001'"); System.out.println("\n原始DELETE SQL:" + originalDeleteSql); System.out.println("改写后DELETE SQL:" + processedSql); // 输出:DELETE FROM user WHERe id = 123 AND dept_id = '001' } catch (Exception e) { e.printStackTrace(); } // 示例3:校验失败场景(DELETe无WHERe) try { String riskyDeleteSql = "DELETE FROM user"; engine.processSql(riskyDeleteSql, 0, ""); } catch (IllegalArgumentException e) { System.out.println("\n校验失败:" + e.getMessage()); // 输出:校验失败:DELETE语句必须包含WHERe条件 } catch (Exception e) { e.printStackTrace(); } }}四、引擎扩展建议
你可以基于这个基础引擎,根据业务需求扩展更多功能:
- 分库分表适配:解析 SQL 中的分片字段(如 user_id),改写表名(如 user → user_12);
- 数据脱敏改写:解析 SELECT 中的敏感字段(如 phone),替换为脱敏函数(如 CONCAt (LEFt (phone,3),'****',RIGHt (phone,4)));
- 读写分离路由:识别 SELECT 语句,改写表名前缀(如 user → user_slave);
- 慢 SQL 预警:解析 JOIN/ORDER BY 等子句,识别无索引的字段访问;
- 跨库语法兼容:将 Oracle 的 ROWNUM 改写为 MySQL 的 LIMIT,或将 MySQL 的 ConCAT 改写为 Oracle 的 ||。
五、关键注意事项
- 异常处理:JSqlParser 解析非法 SQL 会抛出JSQLParserException,需捕获并友好提示;
- AST 遍历:复杂 SQL(如子查询、联表)需递归遍历 AST 节点,可使用 JSqlParser 的expressionVisitor/StatementVisitor接口;
- 性能优化:高频解析场景可缓存解析结果,或使用批量解析;
- 兼容性:不同数据库的 SQL 语法差异(如 MySQL vs PostgreSQL),需在改写时做适配。
总结
基于 JSqlParser 构建 SQL 分析与改写引擎的核心要点:
- 核心流程:SQL 字符串 → 解析为 AST → 校验 / 改写 AST → 生成新 SQL;
- 核心能力:通过操作 AST 实现精准的 SQL 校验和改写(而非字符串替换);
- 扩展思路:基于基础引擎封装业务模块(合规校验、权限控制、分库分表等),保持模块可插拔。
这个引擎框架可直接落地到数据安全、数据库中间件、数据治理等业务场景,你可以根据实际需求增减校验规则和改写逻辑。

