如何执行存在外键依赖顺序问题的无序SQL脚本(ANT构建场景)
免手动调序的无序SQL脚本执行方案
针对这类脚本中关联表插入早于主表插入、触发外键完整性约束报错,且脚本嵌入ANT构建流程不便手动调整顺序的场景,可直接复用以下几种适配方案,全程不需要修改原脚本的语句顺序:
方案1:会话级临时禁用外键约束
这是改动量最小、可直接嵌入现有ANT构建流程的实现方式,相关配置仅对当前数据库连接会话生效,不会持久化修改表的约束配置,也不会影响构建完成后的正式约束校验逻辑:
- 对当前报错对应的H2数据库,可在ANT调用脚本执行的前后分别插入两行配置语句:
- 执行原SQL脚本前运行:
SET REFERENTIAL_INTEGRITY FALSE; - 原脚本全部执行完成后运行:
SET REFERENTIAL_INTEGRITY TRUE;
- 执行原SQL脚本前运行:
- 如果后续数据库发生迁移,同逻辑的会话级配置可直接复用:
- MySQL:执行脚本前设置
SET FOREIGN_KEY_CHECKS = 0;,执行完成后设为SET FOREIGN_KEY_CHECKS = 1; - PostgreSQL:执行脚本前设置
SET session_replication_role = replica;,执行完成后设为SET session_replication_role = origin; - Oracle:逐表临时禁用对应外键约束,脚本执行完成后重新启用即可
- MySQL:执行脚本前设置
注意:该方法执行过程中不会逐句校验外键关联,只要原脚本最终能把所有需要的主表数据都插入完成,就不会触发之前的完整性约束报错。
方案2:构建层自动识别语句做依赖排序
如果不想通过临时关闭约束的方式执行,可以在ANT构建流程中增加一层薄量的脚本预处理逻辑,不需要手动修改原脚本内容:
- 预处理逻辑的核心规则是优先执行所有无外键依赖的主表插入,再执行带外键关联的子表插入:
- 遍历原脚本内的所有INSERT语句,分别识别每条语句对应的插入目标表名
- 根据提前定义的外键关联关系,调低所有引用了其他表主键的关联表插入语句的执行优先级
- 将排序后的语句流传给数据库执行
- 对应给出的示例场景:识别到
PERMISSIONS是无外键依赖的主表,PERMISSIONS_FOR_ROLE是引用PERMISSIONS主键的关联表,就会自动把INSERT INTO permissions (id, name) VALUES (8, 'update');排到关联表插入语句之前执行,全程无人工干预。
方案3:延迟外键约束检查
如果担心临时关闭约束会漏掉脚本本身的数据错误,可以把外键约束的检查时机从“单条语句执行时”调整为“整个事务提交时”,既不依赖调整语句顺序,也不会彻底失去数据校验能力:
- 实现方式是将外键约束调整为
DEFERRABLE INITIALLY DEFERRED模式,再把所有脚本的插入语句放在同一个数据库事务里执行:整个事务执行过程中无论插入顺序如何错乱,只要事务提交时所有被引用的主表数据都存在,约束校验就会通过;如果存在缺失的主表数据,依然会在事务提交时触发报错,不会放过脏数据。 - 现有外键创建语句只需要补充可延迟属性即可实现该模式,不需要改动原脚本里的插入语句顺序。
内容的提问来源于stack exchange,提问作者Praveen Kumar
相关产品推荐
相关产品推荐

