如何通过Spring JdbcTemplate batchUpdate获取批量插入的行数据
JdbcTemplate批量插入Oracle后获取插入数据的方案
针对Spring Boot 2.7.12 + ojdbc8 + Oracle的环境,在JdbcTemplate批量插入无法使用KeyHolder的情况下,可通过以下几种方式取回插入的行数据:
1. 预生成主键(利用Oracle序列)
Oracle的序列可以提前批量生成主键值,将这些主键与业务数据一起插入,插入完成后直接持有主键,无需额外查询:
// 批量获取序列值 List<Long> ids = jdbcTemplate.queryForList( "SELECT YOUR_SEQ.NEXTVAL FROM DUAL CONNECT BY LEVEL <= ?", new Object[]{batchSize}, Long.class ); // 组装插入数据,将预生成的ID与业务字段绑定 List<Object[]> batchArgs = new ArrayList<>(); for (int i = 0; i < dataList.size(); i++) { YourEntity entity = dataList.get(i); batchArgs.add(new Object[]{ids.get(i), entity.getField1(), entity.getField2()}); } // 执行批量插入 jdbcTemplate.batchUpdate( "INSERT INTO YOUR_TABLE(ID, FIELD1, FIELD2) VALUES (?, ?, ?)", batchArgs ); // 此时ids列表就是插入行的主键,可直接关联业务数据
2. 通过唯一业务字段批量查询
如果插入的数据包含唯一业务标识(比如唯一编码、手机号等),插入完成后可通过这些标识批量查询插入的行:
// 先执行批量插入 jdbcTemplate.batchUpdate( "INSERT INTO YOUR_TABLE(FIELD1, FIELD2) VALUES (?, ?)", dataList.stream().map(entity -> new Object[]{entity.getField1(), entity.getField2()}).collect(Collectors.toList()) ); // 提取唯一业务字段,构造IN查询 List<String> uniqueFields = dataList.stream().map(YourEntity::getUniqueField).collect(Collectors.toList()); String inClause = String.join(",", Collections.nCopies(uniqueFields.size(), "?")); // 查询插入的行数据 List<YourEntity> insertedEntities = jdbcTemplate.query( String.format("SELECT ID, FIELD1, FIELD2 FROM YOUR_TABLE WHERE UNIQUE_FIELD IN (%s)", inClause), uniqueFields.toArray(), (rs, rowNum) -> { YourEntity entity = new YourEntity(); entity.setId(rs.getLong("ID")); entity.setField1(rs.getString("FIELD1")); entity.setField2(rs.getString("FIELD2")); return entity; } );
注意:必须确保业务字段的唯一性,否则会查询到无关数据
3. 使用Oracle RETURNING子句批量获取结果
ojdbc8支持Oracle的RETURNING子句,可在批量插入时直接返回指定字段(比如主键),结合CallableStatement实现:
String sql = "INSERT INTO YOUR_TABLE(FIELD1, FIELD2) VALUES (?, ?) RETURNING ID INTO ?"; jdbcTemplate.execute((Connection conn) -> { try (CallableStatement cs = conn.prepareCall(sql)) { // 注册输出参数,用于接收返回的主键 cs.registerOutParameter(3, Types.BIGINT); for (YourEntity entity : dataList) { cs.setString(1, entity.getField1()); cs.setString(2, entity.getField2()); cs.addBatch(); } // 执行批量插入 cs.executeBatch(); // 提取返回的主键 List<Long> insertedIds = new ArrayList<>(); for (int i = 0; i < dataList.size(); i++) { insertedIds.add(cs.getLong(3)); // 重置输出参数,处理下一条 cs.clearParameters(); } // 可根据主键查询完整行数据,或直接关联业务数据 return insertedIds; } });
内容的提问来源于stack exchange,提问作者timgallin
相关产品推荐
相关产品推荐

