You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DB2导入畸形数据时Ingest语句回滚失效问题排查

问题:DB2导入出错时回滚无效,原表数据被部分替换

我有一个Bash Shell脚本用于执行DB2 SQL文件,目的是用指定文件内容完全替换数据库表MY_TABLE的数据。需求是:当导入文件存在错误时,保留原表数据。比如原表有两行数据,导入文件含一行畸形字符串数据,预期原表内容不变,但实际有效行替换了原表数据。脚本中已关闭自动提交,设置出错停止,错误时执行回滚命令,但回滚未生效,请问脚本问题出在哪里?

附script.ksh代码

SQL_FILE=/app/scripts/script.db2
LOG=/app/logs/script.log

# ...
# 数据库连接初始化代码
# ...

# +c: 关闭自动提交
# -v: 回显命令
# -s: 出错时停止执行
# -p: 显示交互提示符(用于调试)
# -td@: 使用'@'作为SQL文件中的语句分隔符
db2 +c -s -v -td@ -p < $SQL_FILE >> $LOG

if [ $? -gt 2 ];
then echo "发生错误;正在回滚数据" >> $LOG
db2 "ROLLBACK" >> $LOG
exit 1
fi

# 无错误则提交更改
db2 "COMMIT" >> $LOG

附script.db2代码

ingest from file '/app/temp/values.csv'
format delimited by ','
(
  $C1    INTEGER EXTERNAL,
  $C2    INTEGER EXTERNAL
)
restart new 'SCRIPT_JOB'
replace into DATA.MY_TABLE
(
  C1,
  C2
)
values
(
  $C1,
  $C2
)@

问题根源与解决办法

1. REPLACE INTO的特性直接导致数据丢失

REPLACE INTO的执行逻辑是先清空目标表所有数据,再插入新数据。哪怕导入中途出错,已经成功插入的有效行会保留,而清空表的操作已经完成——这时候回滚也恢复不了之前的数据,因为清空操作已经在事务内执行了。

2. 脚本回滚逻辑完全无效

当db2命令执行SQL文件出错退出后,当前的DB2会话已经结束。后续单独执行db2 "ROLLBACK"是在一个全新的会话里,这个新会话根本没有需要回滚的事务,所以回滚命令等于白执行。另外,$? -gt 2的判断条件也不准确,DB2的退出码中2就是错误,大于2的场景覆盖不全,会漏掉很多错误情况。

3. INGEST命令的默认行为是分段提交

就算关闭了自动提交(+c),INGEST默认会批量提交数据,处理一部分就提交一部分,导致错误发生前的操作已经无法回滚。


修改方案

方案一:替换REPLACE INTO为DELETE + INSERT组合,控制事务边界

把script.db2改成以下内容,用显式的事务包裹删除和插入操作,一旦出错就回滚整个事务:

-- 出错时自动回滚并退出
WHENEVER SQLERROR ROLLBACK WORK EXIT@

-- 开启事务
BEGIN WORK@

-- 先删除表数据(这一步在事务内)
DELETE FROM DATA.MY_TABLE@

-- 执行导入插入,禁用批量提交确保在一个事务内
ingest from file '/app/temp/values.csv'
format delimited by ','
DISABLE_BULK_INSERT
(
  $C1    INTEGER EXTERNAL,
  $C2    INTEGER EXTERNAL
)
restart new 'SCRIPT_JOB'
insert into DATA.MY_TABLE
(
  C1,
  C2
)
values
(
  $C1,
  $C2
)@

-- 无错误则提交
COMMIT WORK@

方案二:修正脚本的会话一致性问题

如果要保留脚本的回滚逻辑,必须保证回滚在同一个DB2会话中执行。可以用here-doc方式把所有操作放在同一个会话里:

SQL_FILE=/app/scripts/script.db2
LOG=/app/logs/script.log

# ...
# 数据库连接初始化代码
# ...

# 用here-doc执行所有操作,保证会话一致
db2 +c -s -v -td@ -p >> $LOG << EOF
BEGIN WORK@

DELETE FROM DATA.MY_TABLE@

ingest from file '/app/temp/values.csv'
format delimited by ','
DISABLE_BULK_INSERT
(
  \$C1    INTEGER EXTERNAL,
  \$C2    INTEGER EXTERNAL
)
restart new 'SCRIPT_JOB'
insert into DATA.MY_TABLE
(
  C1,
  C2
)
values
(
  \$C1,
  \$C2
)@

COMMIT WORK@
EOF

# 检查执行结果
if [ $? -ne 0 ]; then
  echo "发生错误;正在回滚数据" >> $LOG
  db2 +c "ROLLBACK WORK" >> $LOG
  exit 1
fi

内容的提问来源于stack exchange,提问作者Xirema

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 05:27:25