必须打印 getmessage() 和 getsqlstate() 获取原始错误和状态码,开启日志显示带参数的完整sql,在数据库cli中独立验证,重点检查保留字引号、大小写、子句顺序及字符串/日期格式。

遇到 SQLSyntaxErrorException,别急着改 SQL 字符串——它是个受检异常,但真正线索不在异常类型本身,而在驱动返回的原始错误信息和执行上下文。定位关键不是“猜哪错了”,而是“让数据库自己告诉你错在哪”。
必须打印 getMessage() 和 getSQLState()
异常对象的 getMessage() 是第一手证据,几乎原样包含数据库返回的提示,比如:
-
ERROR: column "user_nam" does not exist(PostgreSQL,拼写少个 e) -
You have an error in your SQL syntax near 'ORDER BY'(MySQL,语法断点明确) -
Unknown database 'mydb'或Table 'test.users' doesn't exist
getSQLState() 是快速分类器:42000 表示语法错误,28000 是权限问题,08001 是连接失败。只打 e.toString() 会丢掉这些关键字段。
拿到带参数的真实 SQL,别信预编译占位符
你写的 "SELECT * FROM user WHERE id = ?" 不是数据库执行的语句。要看到真实执行内容:
- MyBatis:启用
logging.level.org.apache.ibatis=DEBUG,日志里会输出拼接后 SQL 和参数值 - MySQL JDBC:URL 加
&profileSQL=true&logger=com.mysql.cj.log.StandardLogger - PostgreSQL JDBC:URL 加
&logLevel=2 - Spring Boot + JdbcTemplate:
logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
在数据库 CLI 中独立验证,绕过 Java 层干扰
把日志里捞出的完整 SQL 复制进 psql、mysql -u root -p 或 DBeaver 直接运行。原因很实在:
- PreparedStatement 防注入,不防语法错——漏括号、错关键字、引号类型不对,照样报错
- MySQL 用反引号
`order`,PostgreSQL 要双引号"order",H2 的SERIAL只在 PG 模式生效 - MyBatis 动态 SQL 可能拼出
WHERE AND name = 'a'这类非法结构,<where></where>不校验逻辑合法性
盯紧四类高频雷区
80% 的语法错集中在这几个位置:
-
保留字未加引号:列名或表名用了
order、group、date,不同库引号规则不同 -
大小写与拼写:PostgreSQL 默认区分大小写;
user_nam少个 e,驱动不会提示 -
子句顺序硬性要求:PostgreSQL 必须
OFFSET ? LIMIT ?,MySQL 支持LIMIT ?, ? -
字符串/日期常量未闭合:单引号漏了、嵌套引号没转义、日期格式错(如 MySQL 要
'2026-06-04',不能是'06/04/2026')
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











