
MyBatis 使用 BATCH 模式执行 Oracle 批量更新时,BatchResult.getUpdateCounts() 返回全为 -2 的数组,导致无法准确统计实际影响行数;这是 Oracle JDBC 驱动对 PreparedStatement 批处理的固有限制,而非 MyBatis 或业务逻辑错误。
mybatis 使用 batch 模式执行 oracle 批量更新时,`batchresult.getupdatecounts()` 返回全为 -2 的数组,导致无法准确统计实际影响行数;这是 oracle jdbc 驱动对 preparedstatement 批处理的固有限制,而非 mybatis 或业务逻辑错误。
在 Oracle 数据库中,当使用 PreparedStatement(MyBatis 默认采用的方式)进行 JDBC 批处理(addBatch() + executeBatch())时,JDBC 规范明确规定:无法获取每条语句实际影响的行数。Oracle 官方文档明确指出,此时 getUpdateCounts() 返回的数组中每个元素均为 -2 —— 这是 JDBC 标准定义的特殊值,表示“操作成功,但影响行数未知”(Statement.SUCCESS_NO_INFO)。
这正是你观察到 updateCnt = -6(3 条语句 × -2)的根本原因。而 MySQL 能返回真实计数,是因为其 JDBC 驱动对 PreparedStatement 批处理支持更宽松的行数反馈,但这并非跨数据库通用行为。
✅ 正确理解与应对策略
- 不要依赖 getUpdateCounts() 判断执行结果:尤其在 Oracle 环境下,该数组不具备业务校验价值;
- 改用事务一致性 + 业务逻辑兜底验证:例如通过主键/唯一键确保幂等性,或在更新后执行 SELECT COUNT(...) 校验预期变更;
- 若强需行数反馈,可考虑绕过批处理(不推荐):逐条执行 session.update() 并捕获单次返回值(牺牲性能,破坏批量初衷);
- 避免误配连接参数:如 defaultBatchValue 等非标准 Oracle JDBC 参数无效,Oracle 不支持通过 URL 参数启用 PreparedStatement 批量行数统计。
? 示例:安全的批量更新校验写法(推荐)
try (SqlSession session = sessionFactory.openSession(ExecutorType.BATCH, false)) {
for (Map<String, Object> data : selectList) {
session.update(mapperId + "." + updateId, data);
}
// ⚠️ 忽略 -2,仅确认无异常
session.flushStatements(); // 触发执行,抛出异常则中断
// ✅ 业务级校验:例如检查关键字段是否已按预期更新
int actualUpdated = session.selectOne("yourMapper.checkUpdatedCount", param);
if (actualUpdated != selectList.size()) {
session.rollback();
throw new IllegalStateException("Expected " + selectList.size()
+ " rows updated, but found " + actualUpdated);
}
session.commit();
}? 总结
- -2 是 Oracle JDBC 对 PreparedStatement 批处理的标准响应,不是 bug,而是设计使然;
- MyBatis 的 BATCH 模式底层仍基于 PreparedStatement,因此必然继承此限制;
- 解决方案应转向应用层健壮性设计(如幂等校验、事务回滚机制、日志追踪),而非试图从 getUpdateCounts() 中提取不可靠数值;
- 切勿为兼容 Oracle 而降级为 SIMPLE 执行器或手动拼接 SQL —— 这将丧失预编译、防注入和性能优势。
始终牢记:数据库驱动的能力边界,决定了 ORM 层的合理使用方式。


















