批量更新Oracle表时,如何为每行设置不同的随机GUID?
问题描述
需要批量更新Oracle数据库的review_item表多行数据,当前Java代码通过PreparedStatement执行更新,但所有被更新行的target_urn字段都被设置为同一个随机GUID,需求是每行设置不同的随机GUID。当前代码如下:
StringBuilder stringBuilder = new StringBuilder( "UPDATE review_item SET LAST_MODIFIED_TIMESTAMP = systimestamp, ") .append("target_urn = ?, ") .append("assignee_urn = NULL WHERE item_id in (") .append(StringUtils.join(itemIds, ",")) .append(")"); PreparedStatement ps = connection.prepareStatement(stringBuilder.toString()); OracleUtil.bindInput(ps, 1, getRandomUuid(), dbClauses.getQueuePostCleanState());
可行解决方法
方案一:利用Oracle内置函数生成GUID
直接在SQL中使用Oracle自带的SYS_GUID()函数,无需在Java端生成GUID,每行更新时会自动生成唯一值。修改后的代码如下:
StringBuilder stringBuilder = new StringBuilder( "UPDATE review_item SET LAST_MODIFIED_TIMESTAMP = systimestamp, ") .append("target_urn = SYS_GUID(), ") .append("assignee_urn = NULL WHERE item_id in (") .append(StringUtils.join(itemIds, ",")) .append(")"); PreparedStatement ps = connection.prepareStatement(stringBuilder.toString()); ps.executeUpdate();
说明:SYS_GUID()生成的是16字节RAW类型GUID,若target_urn为字符串类型,可改用RAWTOHEX(SYS_GUID())转换为32位十六进制字符串。
方案二:逐行批量更新(适合小数据量场景)
如果必须在Java端生成GUID,可遍历itemIds,为每个ID单独绑定不同的GUID,再批量执行更新:
String sql = "UPDATE review_item SET LAST_MODIFIED_TIMESTAMP = systimestamp, " + "target_urn = ?, assignee_urn = NULL WHERE item_id = ?"; try (PreparedStatement ps = connection.prepareStatement(sql)) { for (Long itemId : itemIds) { String randomUuid = getRandomUuid(); OracleUtil.bindInput(ps, 1, randomUuid, dbClauses.getQueuePostCleanState()); ps.setLong(2, itemId); ps.addBatch(); } ps.executeBatch(); }
说明:使用addBatch()+executeBatch()批量执行,比循环单条执行效率更高,适合数据量不大的场景。
方案三:临时表关联更新(适合大数据量场景)
针对数据量较大的情况,可先将itemId与对应GUID插入临时表,再通过关联临时表完成批量更新:
- 创建临时表(若不存在):
CREATE GLOBAL TEMPORARY TABLE temp_item_guid ( item_id NUMBER, target_urn VARCHAR2(64) ) ON COMMIT DELETE ROWS;
- Java代码批量插入数据到临时表:
String insertSql = "INSERT INTO temp_item_guid (item_id, target_urn) VALUES (?, ?)"; try (PreparedStatement insertPs = connection.prepareStatement(insertSql)) { for (Long itemId : itemIds) { insertPs.setLong(1, itemId); insertPs.setString(2, getRandomUuid()); insertPs.addBatch(); } insertPs.executeBatch(); }
- 执行关联更新:
String updateSql = "UPDATE review_item ri " + "SET ri.LAST_MODIFIED_TIMESTAMP = systimestamp, " + "ri.target_urn = tig.target_urn, " + "ri.assignee_urn = NULL " + "WHERE ri.item_id = tig.item_id"; try (PreparedStatement updatePs = connection.prepareStatement(updateSql)) { updatePs.executeUpdate(); }
说明:临时表会在事务提交后自动清空数据,这种方式效率远高于逐行更新,适合大规模数据处理。
内容的提问来源于stack exchange,提问作者Mahima Vuppuluri
相关产品推荐
相关产品推荐

