栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java解析SQL的基本思路

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java解析SQL的基本思路

天天在写sql,一直很好奇sql到底咋解析的,于是随便整个小demo。

比如sql是:

String sql = "select name,score,sex from users where name = 'jack' and isdelete <> 1 ; ";

中间可能有1个或者多个空格,就想着怎么着也得有个分词的类,就叫做Tokenizer吧。

public class Tokenizer implements Iterator {

    String[] tokens;

    int index = 0;

    public Tokenizer(String sql) throws BadSqlGrammarException {

        sql = sql.trim();

        if (!sql.endsWith(";")) {

            throw new BadSqlGrammarException("SQL未正确结束!");

        }

        //去除多余的空格
        sql = sql.replace(";", " ;").replaceAll("\s+", " ");

        //分词
        tokens = sql.split(" ");


    }


    @Override

    public boolean hasNext() {

        return index < tokens.length;

    }

    @Override

    public String next() {

        return tokens[index++];

    }

}

实现Iterator是因为需要去遍历维护的String数组,方便后面解析。

然后是parser类,里面聚合一个Tokenizer的引用。

public class Parser {

    Tokenizer tokenizer;

    DBCmd cmd;

    Map cmdMap = new HashMap<>();


    public Parser(String sql) throws BadSqlGrammarException {

        //用查表法,代替一大堆的if else

        this.cmdMap.put("select", new SelectCmd());


        this.tokenizer = new Tokenizer(sql);


        //根据第一个sql关键字来确定是什么sql命令

        this.cmd = this.cmdMap.get(tokenizer.next());


        if (cmd == null)

            throw new BadSqlGrammarException("未识别的sql命令!");


    }


    public void query() throws BadSqlGrammarException {

        cmd.query(tokenizer);

    }


}

DBCmd做成一个抽象类,不同的命令需要单独设计一个类,去继承他。DBCmd就弄一些通用的方法即可。

public abstract class DBCmd {


    public abstract void query(Tokenizer tokenizer) throws BadSqlGrammarException;


    protected String splitUntilEnd(Tokenizer tokenizer) throws BadSqlGrammarException {

        return splitUntil(tokenizer, ";");

    }


    protected String splitUntil(Tokenizer tokenizer, String until) throws BadSqlGrammarException {

        StringBuffer sb = new StringBuffer();

        boolean find = false;

        while (tokenizer.hasNext()) {

            String next = tokenizer.next();

            if (!next.equals(until)) {

                sb.append(next).append(" ");

                continue;

            } else {

                find = true;

                break;

            }

        }

        if (!find)

            throw new BadSqlGrammarException("语法不正确");


        return sb.toString();


    }

}

只测试一下select语法,所以只写一个select操作类。

public class SelectCmd extends DBCmd {


    @Override

    public void query(Tokenizer tokenizer) throws BadSqlGrammarException {

        String querys = splitUntil(tokenizer, "from");

        String tableName = tokenizer.next();

        String condition = null;

        if (tokenizer.hasNext() && tokenizer.next().equals("where")) {

            condition = splitUntilEnd(tokenizer);

        }

        System.out.println("查询字段:" + querys);

        System.out.println("查询表:" + tableName);

        System.out.println("查询条件:" + condition);

    }


}

最后测试一下子:

public static void main(String[]args)throws BadSqlGrammarException{

        String sql="select  name,score,sex from    users where name = 'jack' and isdelete <> 1   ;  ";

        Parser parser=new Parser(sql);

        parser.query();

}

效果:

查询字段:name,score,sex
查询表:users
查询条件:name = 'jack' and isdelete <> 1

仔细一想,如果涉及到连表,where条件多层嵌套,甚至子查询,就GG了。实在是够复杂的。本文仅为抛砖引玉,匿了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/836601.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号