oracle jdbc驱动不支持rewritebatchedstatements=true,该参数仅适用于mysql;其批量优化应依赖addbatch()/executebatch()、合理batchsize(建议50–300)、sequence缓存配置及事务控制。

saveAll() 不是 Oracle 的银弹,直接套用 Spring Data JPA 默认配置反而可能变慢。Oracle 对批量插入有明确的 JDBC 行为差异,必须针对性调优。
Oracle JDBC 驱动必须启用 rewriteBatchedStatements=true?
不是。这是 MySQL 特有的优化参数,对 Oracle 无效,甚至会导致连接失败或静默忽略。Oracle 的批处理依赖 PreparedStatement.addBatch() + executeBatch() 原生机制,且需显式设置 setBatchSize()(非 Hibernate 配置项)。
关键点:
• Oracle 官方 JDBC 驱动(ojdbc8.jar)默认不合并 SQL,每条 addBatch() 就是一次逻辑批操作;
• 必须配合 connection.setAutoCommit(false) 手动控制事务边界;
• executeBatch() 返回的 int[] 数组要检查,Oracle 可能返回 EXECUTE_FAILED(-3),不能只看长度。
saveAll() 在 Oracle 上为什么比单条还慢?
因为默认开启的 spring.jpa.hibernate.ddl-auto=none 下,Hibernate 仍会为每条实体生成独立 INSERT,并在 saveAll() 内部循环调用——这本质仍是 N 次单条提交,还多了一层代理开销。
真正生效的前提:
• 实体主键策略必须是 @GeneratedValue(strategy = GenerationType.SEQUENCE)(Oracle 推荐),禁用 IDENTITY(Oracle 不支持自增主键的 JDBC 批处理);
• 显式配置 spring.jpa.properties.hibernate.jdbc.batch_size=50;
• 关闭 Hibernate 的二级缓存写入(spring.jpa.properties.hibernate.cache.use_second_level_cache=false),否则每条 insert 都触发缓存同步。
分批大小设成 1000 是否合理?
不合理。Oracle 的 executeBatch() 在 batch size > 256 时容易触发 PGA 内存溢出(ORA-04030),尤其当字段较多或含 CLOB/BLOB 时。
实测建议值:
• 纯 VARCHAR2/NUMBER 字段:batchSize = 200~300;
• 含单个 CLOB 字段:batchSize ≤ 50;
• 使用 OracleConnection.setImplicitCachingEnabled(true) 可略微放宽上限,但需配套调整数据库端 session_cached_cursors 参数;
• 永远不要让单个 batch 超过 500 条,Oracle 的批处理不是“越大越好”。
并行线程数怎么定?
不是 CPU 核数 × 2。Oracle 的序列(SEQUENCE)争用是隐性瓶颈:多个线程同时请求同一 sequence.nextval 会排队等待,线程越多,锁等待越长。
安全做法:
• 先评估 sequence 的 cache 值(SELECT cache_size FROM user_sequences WHERE sequence_name = 'XXX');
• 若 cache_size = 20,则并发线程数不应超过 20,否则大量线程卡在 sequence 获取上;
• 更稳妥的方式:每个线程独占一个 sequence(如 seq_1, seq_2…),或改用 UUID + 序列号拼接避免争用;
• HikariCP 连接池的 maximumPoolSize 必须 ≥ 并发线程数,否则线程阻塞在 getConnection()。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











