这些不变量需要什么样的隔离级别?

时间:2014-04-29 12:57:51

标签: sql postgresql

我有两个表,TabelATabelB。两者都有ID列作为主键。此外,TabelB列有A_ID列。其他栏目与此无关。

create table TableA (
    ID serial primary key,
    ...,
)
create table TableB (
    ID serial primary key,
    A_ID integer not null references TableA(ID),
    ...,
)

对于TabelA中的每一行,TableB中可能有许多行使用A_ID列引用它。这意味着TableATableB中的行具有父子关系。我希望能够在TableA及其TableB中的所有关联行(即整个"系列")中替换一行。

ID=old_id替换行的SQL如下所示:

delete from TableA where ID=old_id;
delete from TableB where A_ID=old_id;
insert into TableA values (default, ...);
-- get the new id somehow
insert into TableB values (default, new_id, ...), (default, new_id, ...), ...;

(省略号代表其余列。)

我需要设置哪个隔离级别来保证如果执行此代码的两个事务重叠,则在完成后保持以下内容:

  1. TableA ID=old_id中没有行。
  2. TableB中的所有行都A_ID也显示在ID的{​​{1}}列中(特别是TableA中没有行TableB)。
  3. 只有一个交易在A_ID=old_id中恰好插入了一行。
  4. 只有一个交易将任何行插入TableA,所有行都有TableB,其中A_ID=new_id是插入3行的new_id
  5. 我也愿意接受更改代码的建议。

2 个答案:

答案 0 :(得分:1)

即使是你的第一个要求,你也需要一种可序列化隔离的形式,因为其他任何东西都可以随时出现。如果删除所有现有行,并且有人插入新行,则可能会出现异常。

请参阅“Phantom Reads”。请注意,Postgres中的< 9.1“SERIALIZABLE”级别不提供文档明确调用的可序列化。

答案 1 :(得分:0)

您应该在TableA的行之前删除TableB的行。此外,A_ID应该是正确的外键。您可以然后使用级联创建此密钥,以便从TableA中删除自动级联到TableB(并删除记录),但我个人认为这对于复杂的DB方案有点可怕并且反向删除编程。

删除/插入块之后的简单BEGINCOMMIT就足够了。在此块完成之前启动的任何内容都将看到数据库处于旧状态,之后的任何内容都将看到新状态。