Может ли операция INSERT привести к взаимоблокировке?
предполагая, что:
- я использую REPEATABLE_READ или СЕРИАЛИЗУЕМУЮ изоляцию транзакций (блокировки сохраняются каждый раз, когда я получаю доступ к строке)
- мы говорим о нескольких потоках, обращающихся к нескольким таблицам одновременно.
у меня есть следующие вопросы:
-
возможно ли для
INSERTоперация для создания тупика? если да, пожалуйста, предоставьте подробный сценарий, демонстрирующий, как тупик может (например, поток 1 делает это, поток 2 делает это,..., тупик.) - для бонусных очков: ответьте на тот же вопрос для всех других операций (например, выберите, обновите, удалите).
обновление: 3. Для супер бонусных очков: как я могу избежать тупика в следующем сценарии?
приведенный таблицы:
- разрешения
[id BIGINT PRIMARY KEY] - С
[id BIGINT PRIMARY KEY, name VARCHAR(30), permission_id BIGINT NOT NULL, FOREIGN KEY (permission_id) REFERENCES permissions(id))
Я создаю новую компанию как следует:
- вставить в разрешения; -- вставить разрешения.id = 100
- вставить в значения companies (name, permission_id) ('Nintendo', 100); -- вставить companies.id = 200
Я удаляю компанию следующим образом:
- выберите permission_id из компаний, где id = 200; -- возвращает permission_id = 100
- удалить из компаний, где id = 200;
- удалить из разрешений, где id = 100;
в приведенном выше примере порядок блокировки вставки - [разрешения, компании] , тогда как порядок блокировки удаления - [компании, разрешения]. Есть ли способ исправить этот пример для REPEATABLE_READ или SERIALIZABLE изоляция?
3 ответов
как правило, все изменения могут привести к взаимоблокировке и выбирает не будут (об этом позднее). Так что
- нет, вы не можете игнорировать эти.
- вы можете несколько игнорировать выбор в зависимости от вашей базы данных и настроек, но другие дадут вам тупики.
вам даже не нужно несколько таблиц.
лучший способ создать тупик-сделать то же самое в другом порядке.
SQL Server примеры:
create table A
(
PK int primary key
)
сеанс 1:
begin transaction
insert into A values(1)
Сессия 2:
begin transaction
insert into A values(7)
сеанс 1:
delete from A where PK=7
Сессия 2:
delete from A where PK=1
вы получите тупик. Так что доказанные вставки и удаления могут взаимоблокировки.
обновления аналогичны:
сеанс 1:
begin transaction
insert into A values(1)
insert into A values(2)
commit
begin transaction
update A set PK=7 where PK=1
Сессия 2:
begin transaction
update A set pk=9 where pk=2
update A set pk=8 where pk=1
сеанс 1:
update A set pk=9 where pk=2
тупик!
SELECT никогда не должен взаимоблокировки, но на некоторых базы данных это будет, потому что блокировки, которые он использует, мешают последовательному чтению. Это просто дерьмовый дизайн Database engine.
SQL Server не будет блокировать SELECT при использовании изоляции моментальных снимков. Oracle и я думаю, что Postgres никогда не будет блокировать SELECT (если у вас нет обновления, которое явно резервируется для обновления в любом случае).
поэтому в основном я думаю, что у вас есть несколько неправильных предположений. Кажется, я доказал:
- обновления может привести к тупики
- удаление может привести к блокировкам
- вставки могут вызвать блокировки
- вам не нужно больше одной таблицы
- вы do требуется более одного сеанса
вы просто должны принять мое слово на SELECT ;), но это будет зависеть от вашей БД и настроек.
в дополнение к ответу LoztInSpace,inserts может привести к блокировкам даже без deletes или updates наличие. Все, что вам нужно, это уникальный индекс и обратный порядок операций.
пример в Oracle :
create table t1 (id number);
create unique index t1_pk on t1 (id);
--thread 1 :
insert into t1 values(1);
--thread 2
insert into t1 values(2);
--thread 1 :
insert into t1 values(2);
--thread 2
insert into t1 values(1); -- deadlock !
предположим, у вас есть два отношения A и B и двух пользователей X и Y. Таблица A заблокирована пользователем X, а таблица B заблокирована Y. тогда следующий запрос даст вам мертвую блокировку, если он используется как пользователями X, так и Y.
Select * from A,B
так явно Select операция может вызвать взаимоблокировку, если операции соединения, включающие более одной таблицы, являются ее частью. Обычно операции Insert и Delete включают одиночные отношения. Поэтому они могут не вызывать тупик.