【问题标题】:Violating foreign key constraint with deferred constraint使用延迟约束违反外键约束
【发布时间】:2020-06-10 00:33:55
【问题描述】:

我正在尝试将我的 sql 脚本设置为一个事务,以实现我的数据库的原子性。

表结构为(简化):

CREATE TABLE foo (
    id serial  NOT NULL,
    foo varchar(50)  NOT NULL,    
    CONSTRAINT foo_pk PRIMARY KEY (id)
);

CREATE TABLE access (
    id serial  NOT NULL,
    foo_id int  NULL
    CONSTRAINT access_pk PRIMARY KEY (id)
);

ALTER TABLE access ADD CONSTRAINT access_foo
    FOREIGN KEY (foo_id)
    REFERENCES foo (id)
    ON DELETE  CASCADE 
    ON UPDATE  CASCADE 
    DEFERRABLE 
    INITIALLY DEFERRED;

在我的代码中,我首先声明: client.query('BEGIN');(我正在使用 npm 库 'pg')然后 将一行插入到表“foo”中,然后另一个插入到“访问”中,并使用第一个插入的 foo_id。之后有client.query('COMMIT');

所有这些都在 try catch 中,并且在 catch 中是 client.query('ROLLBACK'); 并且如果任一插入出现问题,回滚似乎正在工作。当所有事情都应该提交时,我仍然会为此进入 catch 块:

消息:“在表“access”上插入或更新违反了外键约束“access_foo””

详细信息:“表“foo”中不存在键 (foo_id)=(20)。”

我认为延迟约束就足以做到这一点,但我想我错了。欢迎任何帮助。

【问题讨论】:

  • PostgreSQL 中的 DEFERRABLE INITIALLY DEFERRED 在事务结束时验证外键约束。我猜你的事务划分有问题。
  • 在错误消息中实际上您需要了解的内容非常多:Key (foo_id)=(20) is not present in table "foo" 所以您要插入访问 foo_id=20 但在那里没有 id=20 的行。您的 INSERT INTO 费用很可能失败。
  • 请注意,您不能DELETE 父记录,然后在提交之前重新插入它,当孩子存在时。我学得很辛苦。

标签: sql node.js postgresql


【解决方案1】:

您可能对事务划分有一些问题。我进行了一个简单的测试并且效果很好。

insert into foo (id, foo) values (1, 'Anne');

start transaction;

insert into access (id, foo_id) values (101, 1);

insert into access (id, foo_id) values (107, 7); -- 7 does not exist yet...

insert into foo (id, foo) values (7, 'Ivan'); -- 7 now exists!

commit; -- at this point all is good

请参阅DB Fiddle 的运行示例。

【讨论】:

  • 谢谢,这引导我走向正确的方向,我发现了我的问题。我没有正确使用 pg pool。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-09
  • 2018-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多