我有两个表,TabelA
和TabelB
。两者都有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
列引用它。这意味着TableA
和TableB
中的行具有父子关系。我希望能够在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, ...), ...;
(省略号代表其余列。)
我需要设置哪个隔离级别来保证如果执行此代码的两个事务重叠,则在完成后保持以下内容:
TableA
ID=old_id
中没有行。TableB
中的所有行都A_ID
也显示在ID
的{{1}}列中(特别是TableA
中没有行TableB
)。A_ID=old_id
中恰好插入了一行。TableA
,所有行都有TableB
,其中A_ID=new_id
是插入3行的new_id
。我也愿意接受更改代码的建议。
答案 0 :(得分:1)
即使是你的第一个要求,你也需要一种可序列化隔离的形式,因为其他任何东西都可以随时出现。如果删除所有现有行,并且有人插入新行,则可能会出现异常。
请参阅“Phantom Reads”。请注意,Postgres中的< 9.1“SERIALIZABLE”级别不提供文档明确调用的可序列化。
答案 1 :(得分:0)
您应该在TableA的行之前删除TableB的行。此外,A_ID应该是正确的外键。您可以然后使用级联创建此密钥,以便从TableA中删除自动级联到TableB(并删除记录),但我个人认为这对于复杂的DB方案有点可怕并且反向删除编程。
删除/插入块之后的简单BEGIN
和COMMIT
就足够了。在此块完成之前启动的任何内容都将看到数据库处于旧状态,之后的任何内容都将看到新状态。