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

直接看异常的 getMessage() 内容,它几乎总是包含数据库返回的原始错误提示,比如 ERROR: column "user_name" does not exist(PostgreSQL)或 You have an error in your SQL syntax near 'ORDER BY'(MySQL)。别只打 e.toString(),必须显式打印 e.getMessage() 和 e.getSQLState() —— 后者能快速区分是语法错(如 42000)、权限错(28000)还是连接错(08001)。
拿到真实执行的 SQL
PreparedStatement 不会暴露最终语句,你看到的 “SELECT * FROM user WHERE id = ?” 并不是数据库真正执行的。要定位问题,得看到带参数值的完整 SQL:
- MyBatis:在
log4j2.xml或application.yml中开启logging.level.org.apache.ibatis=DEBUG,日志里会输出拼接后的 SQL 和参数值 - 纯 JDBC(MySQL):URL 加参数
&profileSQL=true&logger=com.mysql.cj.log.StandardLogger - 纯 JDBC(PostgreSQL):URL 加
&logLevel=2 - Spring Boot + JdbcTemplate:配置
logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
在数据库 CLI 里独立验证
别依赖 Java 环境调试 SQL。把日志里捞出的完整语句,复制到 DBeaver、Docker 的 psql、mysql -u root -p 或其他对应数据库的命令行工具中直接运行。原因有三:
- 预编译(PreparedStatement)防不了语法错——漏括号、错关键字、引号类型不对,照样报错
- 不同数据库方言差异大:MySQL 的
`name`、PostgreSQL 的"name"、H2 的SERIAL是否启用 PostgreSQL 模式,都影响结果 - MyBatis 动态 SQL 容易拼出非法结构,比如
WHERE AND name = 'a'(<where>只删开头的 AND,不校验逻辑)
重点盯这些高频雷区
很多语法错其实就卡在几个固定位置:
立即学习“Java免费学习笔记(深入)”;
-
保留字没加引号:列名或表名用了
order、group、date等,MySQL 要用反引号`order`,PostgreSQL 要用双引号"order" -
大小写和拼写:PostgreSQL 默认区分大小写;
user_nam少个 e,驱动不会纠错也不会提示建议 -
子句顺序错:PostgreSQL 要求
OFFSET ? LIMIT ?,MySQL 是LIMIT ?, ?或LIMIT ? OFFSET ? -
字符串/日期常量没闭合:单引号漏了、嵌套引号没转义、日期格式不符合数据库要求(如 MySQL 要
'2026-06-04',不能是'06/04/2026')

















