导读:本期聚焦于小伙伴创作的《如何在 JSqlParser 中严格校验 SQL 功能支持并拒绝不兼容语法》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何在 JSqlParser 中严格校验 SQL 功能支持并拒绝不兼容语法》有用,将其分享出去将是对创作者最好的鼓励。

JSqlParser是一款常用的SQL解析工具,能够将SQL语句解析为结构化的语法树,方便开发者进行SQL分析、改写等操作。在实际业务中,我们常常需要限制系统支持的SQL语法范围,拒绝不符合要求的语句,这就需要基于JSqlParser实现严格的语法校验逻辑。

如何在 JSqlParser 中严格校验 SQL 功能支持并拒绝不兼容语法

JSqlParser基础解析流程

JSqlParser的核心解析逻辑由CCJSqlParserUtil类提供,通过调用parse方法可以将SQL字符串转换为对应的语句对象。如果SQL语法不符合JSqlParser的默认支持范围,解析过程会直接抛出异常。

基础的解析示例如下:

import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;

public class BasicParseDemo {
    public static void main(String[] args) {
        String sql = "SELECT id, name FROM user WHERE age > 18";
        try {
            // 解析SQL语句,返回结构化的Statement对象
            Statement statement = CCJSqlParserUtil.parse(sql);
            System.out.println("解析成功,语句类型:" + statement.getClass().getSimpleName());
        } catch (Exception e) {
            System.out.println("解析失败,原因:" + e.getMessage());
        }
    }
}

捕获解析异常拒绝不兼容语法

JSqlParser默认支持的SQL语法覆盖大部分常用场景,但如果遇到不支持的语法,比如某些数据库特有的语法,解析时会抛出JSQLParserException。我们可以通过捕获这个异常,直接拒绝不兼容的SQL语句。

示例代码如下:

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;

public class SyntaxRejectDemo {
    public static boolean validateSql(String sql) {
        try {
            CCJSqlParserUtil.parse(sql);
            return true;
        } catch (JSQLParserException e) {
            // 解析失败说明存在不兼容语法,返回false表示校验不通过
            return false;
        }
    }

    public static void main(String[] args) {
        // 测试一条包含不支持语法的SQL,比如某些数据库特有的CONNECT BY语法
        String unsupportedSql = "SELECT id FROM user CONNECT BY PRIOR id = parent_id";
        boolean isValid = validateSql(unsupportedSql);
        System.out.println("SQL校验结果:" + isValid);
    }
}

自定义校验规则扩展功能支持限制

仅依赖解析异常捕获只能判断语法是否符合JSqlParser的默认支持范围,无法细化到具体功能维度。比如我们需要禁止DELETE语句、只允许查询类语句,就需要在解析成功后对语法树做进一步校验。

我们可以通过判断解析得到的Statement对象类型,实现功能维度的限制:

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.update.Update;

public class CustomValidateDemo {
    // 只允许SELECT语句,拒绝其他类型的SQL
    public static boolean validateOnlySelect(String sql) {
        try {
            Statement statement = CCJSqlParserUtil.parse(sql);
            // 判断语句类型是否为Select,不是则返回false
            if (statement instanceof Select) {
                return true;
            } else if (statement instanceof Delete || statement instanceof Insert || statement instanceof Update) {
                return false;
            }
            return false;
        } catch (JSQLParserException e) {
            return false;
        }
    }

    public static void main(String[] args) {
        String selectSql = "SELECT id FROM user";
        String deleteSql = "DELETE FROM user WHERE id = 1";
        System.out.println("查询SQL校验结果:" + validateOnlySelect(selectSql));
        System.out.println("删除SQL校验结果:" + validateOnlySelect(deleteSql));
    }
}

深度校验语法树节点

如果需要更细粒度的校验,比如禁止SQL中使用子查询、禁止使用某些函数,就需要遍历解析后的语法树节点进行判断。JSqlParser的语法树节点都实现了对应的访问者接口,我们可以通过自定义访问者实现节点遍历。

以下示例实现禁止SQL中使用子查询的校验:

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SubSelect;
import net.sf.jsqlparser.util.TablesNamesFinder;
import net.sf.jsqlparser.visitor.VisitorAdapter;

import java.util.ArrayList;
import java.util.List;

public class DeepValidateDemo {
    // 自定义访问者,收集SQL中的子查询信息
    static class SubSelectVisitor extends VisitorAdapter {
        private List<SubSelect> subSelects = new ArrayList<>();

        @Override
        public void visit(SubSelect subSelect) {
            subSelects.add(subSelect);
            super.visit(subSelect);
        }

        public List<SubSelect> getSubSelects() {
            return subSelects;
        }
    }

    public static boolean validateNoSubQuery(String sql) {
        try {
            Statement statement = CCJSqlParserUtil.parse(sql);
            if (statement instanceof Select) {
                SubSelectVisitor visitor = new SubSelectVisitor();
                ((Select) statement).getSelectBody().accept(visitor);
                // 如果存在子查询则返回false
                return visitor.getSubSelects().isEmpty();
            }
            return true;
        } catch (JSQLParserException e) {
            return false;
        }
    }

    public static void main(String[] args) {
        String sqlWithSubQuery = "SELECT id FROM (SELECT id FROM user WHERE age > 18) tmp";
        String sqlWithoutSubQuery = "SELECT id FROM user WHERE age > 18";
        System.out.println("包含子查询的SQL校验结果:" + validateNoSubQuery(sqlWithSubQuery));
        System.out.println("不包含子查询的SQL校验结果:" + validateNoSubQuery(sqlWithoutSubQuery));
    }
}

校验逻辑整合建议

实际业务中可以将上述几种校验方式整合,形成完整的校验流程:首先调用JSqlParser解析SQL,捕获解析异常拒绝基础不兼容语法;然后判断语句类型,限制允许的操作类型;最后遍历语法树,校验细粒度的语法规则。这样就能实现严格的SQL功能支持校验,准确拒绝所有不兼容的语法。

需要注意的是,JSqlParser的版本不同支持的语法范围会有差异,如果需要支持特定数据库的语法,可以选择对应版本的JSqlParser,或者在自定义校验规则中补充对应语法的兼容处理。

JSqlParserSQL校验语法解析不兼容语法拒绝修改时间:2026-07-18 22:42:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。