MySQL警告可触发并持有于Connection、Statement/PreparedStatement、ResultSet三类对象,其中PreparedStatement执行后产生的语句级警告最常见;需在SQL执行后立即调用getWarnings()遍历并clearWarnings()清除,否则会被后续操作覆盖。

Java 中通过 JDBC 的 getWarnings() 获取 MySQL 事务中的非致命警告,**需要在每个可能产生警告的 Statement/PreparedStatement/Connection 对象上调用,并且必须在后续操作覆盖前及时读取和清除**。MySQL 的警告(如数据截断、隐式类型转换、除零等)通常不会中断执行,但会被缓存在相关对象上,不主动获取就会丢失。
哪些对象能触发并持有警告?
MySQL 驱动(尤其是 8.0+ 版本)将警告按作用域分别存放在:
- Connection:连接级警告(如连接参数不兼容、时区自动调整)
- Statement / PreparedStatement:SQL 执行后产生的语句级警告(最常用,比如 INSERT 超长字段被截断)
- ResultSet:结果集处理时的警告(较少见,如 FETCH 超出范围)
事务中多数警告来自 PreparedStatement.execute() 或 executeUpdate() 后的 Statement 实例。
正确获取警告的操作步骤
关键点:警告是“一次性”的——调用 getWarnings() 返回链表头,之后必须用 clearWarnings() 清空,否则下次调用仍返回旧警告;若中间执行了新 SQL,旧警告会被覆盖。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 执行 SQL 后立即调用
stmt.getWarnings()(不要等到事务 commit 后) - 遍历
SQLWarning链表,用getNextWarning()循环获取全部警告 - 调用
stmt.clearWarnings()防止干扰后续操作 - 注意:
Connection.getWarnings()一般在连接建立后检查一次即可,事务中很少动态新增
示例代码片段:
try (Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("INSERT INTO users(name) VALUES (?)")) {
ps.setString(1, "this_name_is_way_too_long_for_the_column");
ps.executeUpdate(); // 触发 Warning: Data truncated for column 'name'
SQLWarning warning = ps.getWarnings();
while (warning != null) {
System.out.println("SQLState: " + warning.getSQLState());
System.out.println("Message: " + warning.getMessage());
System.out.println("Vendor Code: " + warning.getErrorCode());
warning = warning.getNextWarning();
}
ps.clearWarnings(); // 必须调用
}
MySQL 配置影响警告可见性
默认情况下 MySQL 可能抑制部分警告。确保 JDBC URL 中启用警告支持:
- 添加参数
&useServerPrepStmts=true&cachePrepStmts=true(预编译语句更易暴露警告) - 避免使用
&jdbcCompliantTruncation=false(已废弃,新版驱动默认行为更严格) - 服务端确认
sql_mode不含STRICT_TRANS_TABLES或STRICT_ALL_TABLES—— 否则截断等操作会直接报错而非警告
可通过 SELECT @@sql_mode 查看当前模式。非 STRICT 模式下才更可能生成可捕获的警告。
事务中警告的生命周期与限制
警告本身不参与事务回滚——即使 conn.rollback(),之前获取过的警告信息仍有效;但未读取的警告会在下一条 SQL 执行时被覆盖或丢弃。
- 不能靠事务提交/回滚来“收集”整个事务的警告,必须逐条 SQL 检查
- 批量操作(
addBatch()+executeBatch())中,警告只反映最后一条失败语句的情况,无法定位具体哪条 - MySQL 驱动 8.0.28+ 对
executeBatch()的警告支持更完整,但仍建议单条执行 + 单条检查以保证准确性

















