共计 2148 个字符,预计需要花费 6 分钟才能阅读完成。
错误背景
JSqlParser 是一个流行的 Java 库,用于解析和操作 SQL 语句。当遇到 caused by: net.sf.jsqlparser.parser.parseexception: encountered unexpected token: "." 错误时,通常意味着解析器在处理 SQL 语句时遇到了不符合预期的点号(.)使用方式。

JSqlParser 的基本工作原理是将 SQL 语句解析为抽象语法树(AST),然后可以通过访问者模式遍历和修改这个 AST。当解析器遇到不符合其语法规则的 SQL 时,就会抛出此类异常。
原因分析
点号在 SQL 中有多种用途,包括:
- 表名和列名之间的分隔符(如
table.column) - 函数调用(如
function.parameter) - 别名引用(如
table AS t后使用t.column)
解析失败通常发生在以下情况:
- 点号出现在不支持的上下文中
- 使用了 JSqlParser 版本不支持的 SQL 方言特性
- SQL 语句中包含特殊字符或未正确转义
解决方案
方案 1:SQL 语法修正指南
常见错误 SQL 示例:
SELECT * FROM users WHERE user.name = 'test' AND user.age > 20;
修正后:
SELECT * FROM users WHERE name = 'test' AND age > 20;
或者明确指定表别名:
SELECT u.* FROM users u WHERE u.name = 'test' AND u.age > 20;
方案 2:JSqlParser 版本适配建议
| JSqlParser 版本 | 支持的点号用法 |
|---|---|
| 1.4 及以下 | 基本表. 列语法 |
| 2.0-3.2 | 增加函数调用支持 |
| 4.0+ | 完整 SQL 标准支持 |
建议升级到最新稳定版(目前是 4.5)。
方案 3:自定义 StatementVisitor 实现
public class CustomSqlVisitor extends StatementVisitorAdapter {
@Override
public void visit(PlainSelect plainSelect) {
// 处理 SELECT 语句中的点号问题
for (SelectItem selectItem : plainSelect.getSelectItems()) {if (selectItem instanceof SelectExpressionItem) {Expression expression = ((SelectExpressionItem) selectItem).getExpression();
processExpression(expression);
}
}
super.visit(plainSelect);
}
private void processExpression(Expression expression) {if (expression instanceof Column) {Column column = (Column) expression;
// 检查并修正点号使用
if (column.getColumnName().contains(".")) {String[] parts = column.getColumnName().split("\\.");
column.setColumnName(parts[parts.length - 1]);
if (parts.length > 1) {column.setTable(new Table(null, parts[0]));
}
}
}
}
}
使用方式:
String sql = "SELECT user.name FROM users";
CCJSqlParserManager parserManager = new CCJSqlParserManager();
Statement statement = parserManager.parse(new StringReader(sql));
statement.accept(new CustomSqlVisitor());
避坑指南
- 避免隐式点号使用:
- 错误示例:
SELECT table.column FROM table(当 column 不存在于 table 时) -
修正:明确表别名或检查列名是否存在
-
函数调用中的点号:
- 错误示例:
SELECT my.function(arg) -
修正:确认函数名是否支持点号分隔
-
转义特殊字符:
- 错误示例:
SELECTtable.columnFROM table - 修正:使用正确的转义语法(取决于数据库)
性能考量
| 解决方案 | 解析时间(ms) | 内存占用(MB) |
|---|---|---|
| 语法修正 | 10-50 | 5-10 |
| 版本升级 | 5-30 | 5-15 |
| 自定义解析 | 20-100 | 10-20 |
建议:对于简单问题优先使用语法修正,复杂场景考虑版本升级,最后才选择自定义解析。
动手实践
尝试扩展上述CustomSqlVisitor,增加对以下 SQL 的支持:
SELECT schema.table.column FROM schema.table
提示:
1. 修改 processExpression 方法处理三级点号分隔
2. 考虑 Table 类的 setSchemaName 方法
3. 测试各种组合情况(schema.table.column, table.column, column)
通过这个练习,你可以更深入理解 JSqlParser 的解析机制,并为实际项目中的复杂 SQL 解析需求做好准备。
正文完
