目录
-
Maven 引用
-
远程仓库
-
依赖包
-
SQL解析
-
获取SQL中的信息
-
创建Select的方式
-
Insert 插入字段和值
-
where条件中字段替换
-
解析SQL例子
-
校验SQL
-
总结
JSqlparser
github地址
JSqlParser is a SQL statement parser. It translates SQLs in a traversable hierarchy of Java classes. JSqlParser is not limited to one database but provides support for a lot of specials of Oracle, SqlServer, MySQL, PostgreSQL … To name some, it has support for Oracles join syntax using (+), PostgreSQLs cast syntax using ::, relational operators like != and so on.
JSqlParser 是SQL语句分析的插件,他使用Java语言去解析SQL。
sqlparser提供很多的数据库语法解析支持其中支持很多oracle的特殊语法。
可以结合mybatis的拦截修改SQL来实现多租户、SQL拼接甚至联表的功能。
可以参考我之前写的MyBatis通过拦截修改SQL
Maven 引用
远程仓库
<repositories>
<repository>
<id>jsqlparser-snapshots</id>
<snapshots>
<enabled>true</enabled>
</snapshots>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
</repositories>
依赖包
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>.4</version>
</dependency>
SQL解析
获取SQL中的信息
public class TestSqlparser {
public static void main(String[] args) throws JSQLParserException {
Select stmt = (Select) CCJSqlParserUtil.parse("SELECT col AS a, col2 AS b, col3 AS c FROM table T WHERE col1 = 10 AND col2 = 20 AND col3 = 30");
Map<String, Expression> map = new HashMap<>();
Map<String, String> mapTable = new HashMap<>();
((PlainSelect) stmt.getSelectBody()).getFromItem().accept(new FromItemVisitorAdapter() {
@Override
public void visit(Table table) {
mapTable.put(table.getAlias().getName(), table.getName());
((PlainSelect) stmt.getSelectBody()).getWhere().accept(new ExpressionVisitorAdapter() {
@Override
public void visit(AndExpression expr) {
System.out.println(expr);
for (SelectItem selectItem : ((PlainSelect)stmt.getSelectBody()).getSelectItems()) {
selectItem.accept(new SelectItemVisitorAdapter() {
@Override
public void visit(SelectExpressionItem item) {
map.put(item.getAlias().getName(), item.getExpression());
System.out.println("map " + map);
System.out.println("mapTables" + mapTable);
创建Select的方式
创建Select(非SQL String 创建)
@Test
public void testCreateSelect () throws JSQLParserException {
Select select = SelectUtils.buildSelectFromTable(new Table("mytable"));
Select select = SelectUtils.buildSelectFromTableAndExpressions(new Table("mytable"), new Column("a"), new Column("b"));
Select select = SelectUtils.buildSelectFromTableAndExpressions(new Table("mytable"), "a+b", "test");
System.out.println(select.toString());
System.out.println(select.toString());
System.out.println(select.toString());
Insert 插入字段和值
@Test
public void testCreateSelect() throws JSQLParserException {
Insert insert = (Insert) CCJSqlParserUtil.parse("insert into mytable (col) values (1)");
System.out.println(insert.toString());
insert.getColumns().add(new Column("col"));
insert.getItemsList().accept(new ItemsListVisitor() {
public void visit(SubSelect subSelect) {
throw new UnsupportedOperationException("Not supported yet.");
public void visit(ExpressionList expressionList) {
expressionList.getExpressions().add(new LongValue());
@Override
public void visit(NamedExpressionList namedExpressionList) {
public void visit(MultiExpressionList multiExprList) {
throw new UnsupportedOperationException("Not supported yet.");
System.out.println(insert.toString());
insert.getColumns().add(new Column("col"));
((ExpressionList) insert.getItemsList()).getExpressions().add(new LongValue());
System.out.println(insert.toString());
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
import net.sf.jsqlparser.util.deparser.SelectDeParser;
import net.sf.jsqlparser.util.deparser.StatementDeParser;
public class ReplaceColumnValues {
static class ReplaceColumnAndLongValues extends ExpressionDeParser {
@Override
public void visit(StringValue stringValue) {
this.getBuffer().append("?");
@Override
public void visit(LongValue longValue) {
this.getBuffer().append("?");
public static String cleanStatement(String sql) throws JSQLParserException {
StringBuilder buffer = new StringBuilder();
ExpressionDeParser expr = new ReplaceColumnAndLongValues();
SelectDeParser selectDeparser = new SelectDeParser(expr, buffer);
expr.setSelectVisitor(selectDeparser);
expr.setBuffer(buffer);
StatementDeParser stmtDeparser = new StatementDeParser(expr, selectDeparser, buffer);
Statement stmt = CCJSqlParserUtil.parse(sql);
stmt.accept(stmtDeparser);
return stmtDeparser.getBuffer().toString();
public static void main(String[] args) throws JSQLParserException {
System.out.println(cleanStatement("SELECT 'abc', FROM mytable WHERE col='test'"));
System.out.println(cleanStatement("UPDATE table A SET A.columna = 'XXX' WHERE A.cod_table = 'YYY'"));
System.out.println(cleanStatement("INSERT INTO example (num, name, address, tel) VALUES (, 'name', 'test ', '1234-1234')"));
System.out.println(cleanStatement("DELETE FROM table where col=5 and col2=4"));
输出:
SELECT ?, ? FROM mytable WHERE col = ?
UPDATE table1 A SET A.columna = ? WHERE A.cod_table = ?
INSERT INTO example (num, name, address, tel) VALUES (?, ?, ?, ?)
DELETE FROM table1 WHERE col = ? AND col2 = ?
where条件中字段替换
替换条件字段col_1到col1
@Test
public void replace () throws JSQLParserException {
Select stmt = (Select) CCJSqlParserUtil.parse("SELECT col AS a, col2 AS b, col3 AS c FROM table WHERE col_1 = 10 AND col_2 = 20 AND col_3 = 30");
System.out.println("before " + stmt.toString());
((PlainSelect)stmt.getSelectBody()).getWhere().accept(new ExpressionVisitorAdapter() {
@Override
public void visit(Column column) {
column.setColumnName(column.getColumnName().replace("_", ""));
System.out.println("after " + stmt.toString());
解析SQL例子
Statement stmt = CCJSqlParserUtil.parse("SELECT * FROM tab");
Statements
stmt = CCJSqlParserUtil.parseStatements("SELECT * FROM tab; SELECT * FROM tab2");
Expression expr = CCJSqlParserUtil.parseExpression("a*(+mycolumn)");
可以直接将String SQL片段解析成Expression再将expr插入到SQL语句中。
获取所有tableNames
Statement statement = CCJSqlParserUtil.parse("SELECT * FROM MY_TABLE");
Select selectStatement = (Select) statement;
TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
List<String> tableList = tablesNamesFinder.getTableList(selectStatement);
自动生成别名
Select select = (Select) CCJSqlParserUtil.parse("select a,b,c from test");
final AddAliasesVisitor instance = new AddAliasesVisitor();
select.getSelectBody().accept(instance);
结果:
SELECT a AS A1, b AS A2, c AS A3 FROM test
SQL函数
单表where条件拼装
JOIN 拼装
校验SQL
String sql = "DROP INDEX IF EXISTS idx_tab_id;";
Validation validation = new Validation(Arrays.asList(DatabaseType.SQLSERVER, DatabaseType.MARIADB,
DatabaseType.POSTGRESQL, DatabaseType.H), sql);
List<ValidationError> errors = validation.validate();
String sql = "CREATE TABLE tab (id NUMERIC(10), val VARCHAR(30))";
Validation validation = new Validation(Arrays.asList(FeaturesAllowed.DML), sql);
List<ValidationError> errors = validation.validate();
log.error (errors);
Validates metadata such as names of tables, views, columns for their existence or non-existence
java.sql.Connection connection = ...;
String sql = "ALTER TABLE mytable ADD price numeric(,5) not null";
Validation validation = new Validation(Arrays.asList(new JdbcDatabaseMetaDataCapability(connection,
NamesLookup.UPPERCASE)), sql);
List<ValidationError> errors = validation.validate();
Statements statements = validation.getParsedStatements();
if (!errors.isEmpty()) {
总结
我们可以借助JSqlparser来解析SQL并且动态拼接生成SQL,在Mybatis-plus中的租户其实也是类似这样实现的。
甚至有兴趣的同学可以自己做一个SQL拼装器,将前台筛选的条件转换为SQL进行查询。所有的查询字段、条件、联表等等都做成动态拼装。