Вставить и удалить в транзакции всегда блокировать строки? - PullRequest
0 голосов
/ 26 мая 2019

У меня есть эта таблица:

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).

В большинстве случаев блокировка до завершения транзакции для удаления обеих строк блокируется, но в некоторых случаях она может перейти к следующей строке, чтобы вставить вторую строку. Если это произойдет, то у меня нет данных о согласованности.

Но я не знаю, так ли это, потому что я делаю некоторые ошибки в тесте или в тех же редких случаях первый запрос не блокируется, как я ожидаю.

Неужели во всех случаях первая вставка должна быть заблокирована, если выполнено первое удаление?

Таблица пуста. Таким образом, кажется, что строка блокируется, когда я пытаюсь удалить, и она не позволяет вставить строку, но я не знаю, могут ли действительно быть некоторые редкие ситуации, в которых строка не блокируется.

Спасибо.

1 Ответ

2 голосов
/ 26 мая 2019
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?

Кажется, вы работаете с уровнем изоляции READ COMMITTED.В этом случае сеанс DELETE не удерживает блокировку, если строки не определены, поэтому сеанс INSERT может приступить к вставке строк.Это становится условием гонки, когда вы можете получить ноль, один или два ряда.Рассмотрим следующую последовательность, которая приводит к одной строке:

--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 является более уязвимым для взаимоблокировок, чем менее ограничивающие уровни изоляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...