java实现sql解析器 JSQLParser
java实现sql解析器 JSQLParser
前言
JSQLParser是基于JavaCC构建的sql语句解析器。它以可遍历的Java类层次结构来转换SQL。而且它不仅限于一个数据库,而且还支持 Oracle, SqlServer, MySQL, PostgreSQL等许多数据库。另外 自 5.0 版本起,JSQLParser 依赖于 Java 11。所以我们需要根据项目依赖环境选取对应的版本。
使用场景
在面对一些内网环境的项目,我们无法访问数据库的情况下,需要快速查一些客户需要的信息时,我们可以在项目中集成JSQLParser 只需要调用接口,就可以可前端配合将数据展示在页面上了。
各种RDBMS 不支持的语法
JSQLParser是一款与关系型数据库(RDBMS) 无关的解析器,专注于符合SQL:2016标准的查询以及“四大数据库”(Oracle,MS SQL Server, Postgres, Mysql/MariaDB)。需要编写可移植且符合标准的SQL。
1.不支持Oracel PL/SQL 块
DECLAREnum NUMBER;
BEGINnum := 10;dbms_output.put_line('The number is ' || num);
END;
- Oracle INSERT ALL…不受支持
INSERT ALLINTO mytable (column1, column2, column_n) VALUES (expr1, expr2, expr_n)INTO mytable (column1, column2, column_n) VALUES (expr1, expr2, expr_n)INTO mytable (column1, column2, column_n) VALUES (expr1, expr2, expr_n)
SELECT * FROM dual;
- DDL 语句
虽然JSQLParser为 DDL 语句提供了大量通用支持,但某些 RDBMS 特定语法(尤其是关于索引、编码、压缩)可能不受支持。
- 区间运算符
不支持任何类似DAY HOUR MINUTE SECOND [TO HOUR MINUTE SECOND]的内容。values cast ((time '12:03:34' - time '11:57:23') minute to second as varchar(8));
快速上手
1.添加依赖(如果我们项目中引入了 mybatis-plus 就不需要添加该依赖了)
<dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>5.1</version>
</dependency>
2.代码实现
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);CCJSqlParserManager ccjSqlParserManager = new CCJSqlParserManager();Statement parse =null;try{parse = ccjSqlParserManager.parse(new StringReader(dto.getSql()));} catch (Exception e) {log.error("SQL执行错误:{}", e.getMessage());
// return e.getMessage();}try {ExecutionSqlVO vo = new ExecutionSqlVO();if (parse instanceof Select) {List<Map<String, Object>> maps = SqlRunner.db().selectList(dto.getSql());Map<String, Object> sqlData = new HashMap<>();sqlData.put("head", CollUtil.isEmpty(maps)? Lists.newArrayList():maps.get(0).keySet());sqlData.put("data", maps);vo.setResult(sqlData);vo.setType(Select.class.getSimpleName());} else if (parse instanceof Update) {Update updateSql = (Update) parse;Expression where = updateSql.getWhere();if (where == null) {throw new ServiceException("禁止执行没有条件的SQL");}boolean update = SqlRunner.db().update(dto.getSql());if(!update){vo.setResult("执行失败");}else {vo.setResult("执行成功");}vo.setType(Update.class.getSimpleName());return vo;} else if (parse instanceof Insert) {boolean insert = SqlRunner.db().insert(dto.getSql());if(!insert){vo.setResult("执行失败");}else {vo.setResult("执行成功");}vo.setType(Insert.class.getSimpleName());} else if (parse instanceof Delete) {Delete deleteSql = (Delete) parse;Expression where = deleteSql.getWhere();if (where == null) {throw new ServiceException("禁止执行没有条件的SQL");}boolean delete = SqlRunner.db().delete(dto.getSql());if(!delete){vo.setResult("执行失败");}else {vo.setResult("执行成功");}vo.setType(Delete.class.getSimpleName());} else if (parse instanceof CreateTable) {jdbcTemplate.execute(dto.getSql());vo.setResult(String.format("执行成功"));vo.setType(Delete.class.getSimpleName());} else {throw new ServiceException("不支持的SQL类型");}return vo;} catch (Exception se) {
// return se.getMessage();}return null;}