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 块
DECLARE
num NUMBER;
BEGIN
num := 10;
dbms_output.put_line('The number is ' || num);
END;
-
Oracle INSERT ALL...不受支持
INSERT ALL
INTO 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;
}
方法测试
