应抓执行前的真实SQL定位SQLException:MySQL加profileSQL=true,PostgreSQL设logLevel=2,Spring Boot配JdbcTemplate=DEBUG;区分SQLTimeoutException(含timeout)与SQLSyntaxErrorException(含ORA-00900等);PreparedStatement不校验列名/表名,需检查拼写、大小写及类型匹配;Connection.isValid()为轻量检测,不代表可执行业务SQL。

SQLException 报错但没看到具体 SQL,怎么快速定位问题
多数 SQLException 不会直接打印出错的 SQL 语句,尤其用 PreparedStatement 时,你看到的只是“ORA-00942”或“MySQLSyntaxErrorException”,根本不知道哪条 SQL 撞上了。关键不是看异常类名,而是抓执行前的真实 SQL。
- 开启 JDBC 驱动日志:MySQL 加
jdbc:mysql://host/db?logger=com.mysql.cj.log.StandardLogger&profileSQL=true;PostgreSQL 用logLevel=2参数 - Spring Boot 用户更简单:在
application.yml加logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG,能打出绑定参数后的完整 SQL - 别信 DAO 层日志里“执行了 update user set name = ?”,那个 ? 还没替换——真正出错的是数据库执行时的最终语句
连接超时(SQLTimeoutException)和语法错误(SQLSyntaxErrorException)怎么一眼区分
这两类异常看着都是 SQLException 子类,但处理路径完全不同:一个是网络/配置问题,一个是代码写错了。光看堆栈容易误判。
-
SQLTimeoutException一定带 “timeout” 或 “socket read timed out”,且通常出现在executeQuery()或executeUpdate()调用处,不是在 prepare 阶段 -
SQLSyntaxErrorException一定含数据库特有错误码:MySQL 是 “You have an error in your SQL syntax”,Oracle 是 “ORA-00900”,PostgreSQL 是 “ERROR: syntax error at or near” - 注意:MyBatis 报
org.apache.ibatis.exceptions.PersistenceException包裹的底层异常才是真凶,得点开Caused by:才能看到是语法错还是超时
PreparedStatement 参数绑定后还报“列不存在”或“类型不匹配”
用了 PreparedStatement 就以为万无一失?其实参数绑定只解决注入和类型转换,不校验列名、表名、函数名这些静态结构。这类错往往在预编译阶段就失败,但有些驱动(如旧版 MySQL Connector/J)会延迟到执行才抛。
- 检查拼写:
SELECT user_name FROM users写成user_nam,驱动不会帮你补全,也不会提示“建议是否是 user_name” - 大小写敏感:PostgreSQL 默认区分大小写,
"UserName"和username是两个东西;MySQL 在 Linux 下也区分表名大小写 - 别把字符串当数字传:
ps.setInt(1, "123")编译不过,但ps.setString(1, "123")传给 INT 字段,某些数据库(如 H2)会静默转,而 MySQL 8.0+ 默认会报data truncation
Connection.isValid() 返回 true 却执行 SQL 失败
这是最骗人的假阳性。连接池(比如 HikariCP)里的连接可能刚被校验过,但紧接着网络抖动、数据库 kill 了该会话、或防火墙中断了长连接,isValid() 校验完下一毫秒就失效了。
立即学习“Java免费学习笔记(深入)”;
-
isValid(1)只发一个轻量 ping,不代表能执行真实业务 SQL——它不走查询计划器,也不校验权限 - 遇到“Connection closed”或“Communications link failure”,别急着重连,先查数据库端有没有
KILL掉这个线程,或看连接池配置的maxLifetime是否小于数据库的wait_timeout - HikariCP 推荐关掉
connectionTestBeforeUse(已废弃),改用connectionInitSql或更可靠的validationTimeout+keepaliveTime
真正难缠的是跨库事务中部分连接失效,或者驱动版本和数据库协议不匹配导致的隐式断连——这时候 SQLException 的 SQLState 可能是 “08S01”,但堆栈里根本没线索,得翻驱动 release note。


















