pgJDBC 强转失败
pgJDBC 42.7.13 的多语句 PreparedStatement batch 可能报 CompositeQuery 强转失败,42.7.14 仍保留相关路径。拆分语句时保留执行顺序、事务与返回值约定。
一份 PreparedStatement 里用分号连接了多条 SQL,调用 executeBatch() 时报 CompositeQuery cannot be cast to SimpleQuery。如果使用 pgJDBC 42.7.13,应检查批处理条目是否是复合查询;已核对的 42.7.14 仍保留这条强制转换路径。
这不表示普通单条 SQL 的 batch 也不能使用。驱动把多语句条目表示为 CompositeQuery,而受影响的批处理循环在展开子语句之前,就把条目当成 SimpleQuery 做接收缓冲估算。
旧版本能执行,也要看具体 SQL 形状
先记录应用实际加载的驱动版本、每个 addBatch() 条目中的语句数量,以及是否包含 RETURNING。连接地址和参数值可能敏感,保留结构与错误即可,不要把完整业务数据写进日志。
42.7.12 的多语句批处理也并非总是可靠。一组语句都返回更新计数时,可能报 Too many update results were returned;带有 RETURNING 的子语句则通过结果行路径处理,曾有能够执行的形状。不能把旧版表现概括成“从来不支持”,也不能因为某组 SQL 以前能执行,就认为更新计数与返回行都已经得到正确处理。
RETURNING 还可能改变异常出现的位置和结果计数行为。不要仅为绕过报错给 SQL 加上它,让本来需要更新计数的调用变成结果查询。
每份 PreparedStatement 保持一条 SQL
较稳妥的调整是拆分复合语句:每份 PreparedStatement 对应一条 SQL,各自保留原参数绑定。适合批处理的单语句可以继续使用 batch;需要返回行的操作则采用能处理结果集的调用,并关闭结果集。
如果多条语句共同完成一次业务操作,应保留原来的执行顺序和事务边界。例如原来每条记录都先插入再清理,不能改成“先批量插入所有记录,再批量清理所有记录”后假定结果相同。
由 Spring 等框架管理事务时,继续交给原事务管理器,不要在其中手动提交或切换连接的 auto-commit。独立管理连接时,需要明确哪些步骤必须一起提交、失败时如何回滚,再按这份约定执行各条语句。
切换 auto-commit 会影响事务,不能在已经进行的操作中随意切换来“重置”连接。调用结束时也应按原连接池或连接所有者的契约恢复状态,不把事务残留交给下一个请求。
CTE 可以在特定 SQL 中组合业务操作,但其快照、依赖和执行语义需要单独审查。不能把任意两条带分号的语句机械包成 CTE,作为通用修复。
异常不证明数据库没有改动
这条内部类型转换异常属于运行时异常,仅捕获 SQLException 的错误清理逻辑可能漏掉它。修正执行方式时,检查现有事务管理与失败处理是否覆盖实际异常,避免错误被吞掉后继续提交。
也不要看到 BatchUpdateException 或强转异常,就直接重试整批写入。此前的条目、旧版的某些子语句或其他业务步骤可能已经执行;应核对事务结果、业务幂等与对应记录,再决定恢复方式。
JDBC 的 SUCCESS_NO_INFO 表示成功但无法取得更新行数,不是零行,也不是可以与其他结果相加的行数。拆分以后重新定义需要验收的更新计数和返回行,不能只检查没有异常。
截至 2026 年 10 月 14 日,已核对的 42.7.14 仍存在上述 batch 循环假设,不能把更新到该版描述为这项问题已经修复。回到 42.7.12 也不是普遍有效的处理,因为 SQL 形状与旧计数问题仍然存在。
在隔离数据上验证正常执行、返回行和中途失败:语句按预期顺序运行,需要原子完成的操作失败后全部回滚,没有重复业务结果。保留应用与 SQL 调整的差异,需要撤回时先确认事务结局,再恢复经过审定的构建,不以删除业务数据代替回退。


