我有此表:
TableAB
{
IDA;
IDB;
}
我想确保始终拥有对(ID1,ID2(和(ID2,ID1(。因此,我试图将其用于脚本:
插入:
begin tran
insert into tablaAB (IDTablaA, IDTablaB) VALUES(1,2);
insert into tablaAB (IDTablaA, IDTablaB) VALUES(2,1);
commit
删除:
begin tran
delete tablaAB where IDTablaA = 1 and IDTablaB = 2
delete tablaAB where IDTablaA = 2 and IDTablaB = 1;
commit
我正在使用Microsoft Management Studio的两个实例来运行两个查询,在大多数情况下,它有效,我得到了这两个行或任何一个。但是有时候,我只得到其中一个。
步骤是:
- 将查询运行到删除(1,2(。
- 运行查询以添加(1,2(。
在大多数情况下,它是封锁的,直到删除两行完成的交易为止,但是在某些情况下,它可以传递到下一行,以插入第二行。如果发生这种情况,那么我没有连贯的数据。
,但我不知道是因为我在测试中犯了一些错误还是在同一罕见情况下,第一个查询不会像我期望的那样被阻止。
实际上,在所有情况下,如果第一个删除完成了?
表是空的。因此,当我尝试删除时,这行似乎被阻塞了,并且不允许插入行,但是我不知道是否真的可以是某些罕见情况,在这些情况下,该行没有被阻止。
谢谢。
But I don't know if it is because I make some mistakes in the test or in same rare cases the first query is not blocked as I expect.
Really in all cases the first insert should be block if the first delete is done?
看来您正在使用读取的隔离级别运行。在这种情况下,当删除会话没有排名时,删除会话没有锁定,因此插入会话可以继续插入行。这将成为一种种族条件,您可能最终以零,一或两排。考虑导致一行的序列:
--session 1:
begin tran;
delete TableAB where IDTablaA = 1 and IDTablaB = 2;
--no row deleted, no lock held
--session 2:
begin tran
insert into TableAB (IDTablaA, IDTablaB) VALUES(1,2);
--row inserted, lock held
insert into TableAB (IDTablaA, IDTablaB) VALUES(2,1);
--row inserted, lock held
commit;
-- inserts committed and locks released
--session 1:
delete TableAB where IDTablaA = 2 and IDTablaB = 1;
--row deleted, lock held
commit;
--deleted committed, lock released
如果您使用SERIALIZABLE
隔离级别,则DELETE
语句将保持锁定(由于没有索引,在这种情况下锁定(并阻止插入会话。将在用于定位要删除的行的列上的索引上保留一个较小的键范围锁。
请注意,SERIALIZABLE
比限制性的隔离水平更容易出现死锁。