PostgreSQL约束延迟判断

两盒软妹~` 提交于 2020-01-19 12:03:16

当我们对一张表上的数据进行操作时,如果该表上有约束存在,那么约束是在什么时候生效的呢?
例如我们在进行数据迁移的时候就会考虑的这个问题,有的迁移工具在迁移的时候必须得将表约束和数据分开迁移,否则会出现数据无法导入的情况,这就是因为约束不能延迟导致的。

那么pg中对于约束的延判有什么原则呢?
1、数据导出时,约束通常是在数据都写入后再创建。避免先创建约束后倒入失败。
2、在使用过程中,PG提供了延迟检测约束的功能:
2.1、允许约束延判,(建表、建约束时可以指定,后续也可以修改)
2.2、设置延判规则,在语句结束还是在事务结束时判断约束。可以通过修改约束定义,或者直接在事务中设置规则。

涉及到以下几个参数:

DEFERRABLE/NOT DEFERRABLE
这两个选项控制了该约束是否能被延迟。一个不可延迟的约束将在每一次命令后立刻被检查,可延迟约束的检查将被推迟到事务结束时进行。

INITIALLY IMMEDIATE/INITIALLY DEFERRED
延迟判断规则,如果该约束是INITIALLY IMMEDIATE,它会在每一个语句之后被检查。这是默认值。如果该约束是INITIALLY DEFERRED,它只会在事务结束时被检查。

我们可以在事务中设置延迟规则:

SET CONSTRAINTS { ALL | name [, ...] } { DEFERRED | IMMEDIATE }

例子:
1、不允许延迟判断

bill@bill=>create table tt1(id int primary key, c1 int);  
CREATE TABLE
bill@bill=>create table tt2(id int references tt1(id), c1 int);    
CREATE TABLE
bill@bill=>insert into tt2 values(1,1); 
ERROR:  insert or update on table "tt2" violates foreign key constraint "tt2_id_fkey"
DETAIL:  Key (id)=(1) is not present in table "tt1".

2、允许延判,并设置延判规则为事务结束

bill@bill=>create table tt3(id int references tt1(id) INITIALLY DEFERRED, c1 int);  
CREATE TABLE

–可以发现在事务中能够插入数据

bill@bill=>begin;
BEGIN
bill@bill=>insert into tt3 values(1,1);
INSERT 0 1

3、允许延判,在事务开启后设置事务结束延判

bill@bill=>alter table tt3 alter CONSTRAINT tt3_id_fkey deferrable;
ALTER TABLE
bill@bill=>begin;
BEGIN
bill@bill=>insert into tt3 values(1,1);
ERROR:  insert or update on table "tt3" violates foreign key constraint "tt3_id_fkey"
DETAIL:  Key (id)=(1) is not present in table "tt1".
bill@bill=>rollback ;
ROLLBACK

bill@bill=>begin;  
BEGIN

–设置事务结束延判, 所有约束生效

bill@bill=>set constraints all  deferred;  
SET CONSTRAINTS
bill@bill=>insert into tt3 values(1,1);
INSERT 0 1
bill@bill=>rollback ;
ROLLBACK
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!