Какой тип Transaction IsolationLevel следует использовать, чтобы игнорировать вставки, но блокировать выбранную строку? - PullRequest
3 голосов
/ 04 августа 2010

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

INSERT INTO Table1 (UserId, StatusTypeId) VALUES (@UserId, 1)

У меня есть второй процесс, который запрашивает Table1 с первого шага, как это:

SELECT TOP 1 * FROM Table1 WHERE StatusTypeId=2

, а затем обновляет эту строку для пользователя. Когда процесс 1 запущен, Table1 заблокирован, поэтому процесс 2 не будет завершен до тех пор, пока не завершится процесс 1, что является проблемой, поскольку вводится длительная задержка, в то время как процесс 1 завершает свой вызов веб-службы.

Процесс 1 будет всегда вставлять StatusTypeId только 1, и это также единственная операция, которая вставляется в Table1. Процесс 2 будет запрашивать только при StatusTypeId = 2. Я хочу сказать, чтобы Процесс 2 игнорировал любые вставки в Таблицу 1, но блокировал выбранную строку. Уровень изоляции по умолчанию для Процесса 2 слишком велик, но у меня есть опасение, что IsolationLevel.ReadUncommitted позволяет читать слишком много грязных данных. Я не хочу, чтобы два пользователя запускали процесс 2, а затем случайно получали одну и ту же строку.

Существует ли другой IsolationLevel для использования, отличный от ReadUncommitted, который говорит, что игнорирует вставленные строки, но удостоверится, что select блокирует выбранную строку?

Ответы [ 2 ]

4 голосов
/ 04 августа 2010

Что касается блокирования SELECT вставкой, этого следует избежать, предоставив соответствующие индексы.

Тестовая таблица.

CREATE TABLE Table1
(
UserId INT PRIMARY KEY,
StatusTypeId INT,
AnotherColumn varchar(50)
)
insert into Table1
SELECT number, (LEN(type)%2)+1, newid()
FROM master.dbo.spt_values
where type='p'

Окно запроса один

BEGIN TRAN
INSERT INTO Table1 (UserId, StatusTypeId) VALUES (5000, 1)
WAITFOR DELAY '00:01';
ROLLBACK

Окно запроса два (Блоки)

SELECT TOP 1 * 
FROM Table1 
WHERE StatusTypeId=2 
ORDER BY AnotherColumn

Но если вы повторите попытку после добавления индекса, он не будет блокировать CREATE NONCLUSTERED INDEX ix ON Table1 (StatusTypeId,AnotherColumn)

Что касается блокировки строк для Process 2, вы можетеиспользуйте следующее (подсказка READPAST позволит 2 одновременным транзакциям Process 2 начать обработку разных строк, а не одну, блокирующую другую).Вы можете найти эту статью Ремуса Русану соответствующей

BEGIN TRAN

SELECT TOP 1 * 
FROM Table1  WITH (UPDLOCK, READPAST)
WHERE StatusTypeId=2
ORDER BY AnotherColumn

/*
Rest of Process Two's code here
*/
COMMIT
4 голосов
/ 04 августа 2010

Редактировать: Перечитав вопрос, блокировка любого insert не должна влиять на select в READ COMMITTED, это может быть проблемой с вашими индексами.

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

Онипредотвращение

  • Dirty Read - чтение незафиксированных данных в транзакции, которую можно откатить - происходит в READ UNCOMMITTED, предотвращается в READ COMMITTED, REPEATABLE READ, SERIALIZABLE

  • Non Repeatable Reads - строка обновляется во время чтения в незафиксированной транзакции, то есть одно и то же чтение определенной строки может происходить дважды в транзакции и приводить к другим результатам - происходит в READ UNCOMMITTED, READ COMMITTED.запрещено в REPEATABLE READ, SERIALIZABLE

  • phantom rows - строка вставляется или удаляется при чтении в незафиксированной транзакции, что означает, что одно и то же чтение нескольких строк может происходить дважды в транзакциии дают разные результаты, с добавленными или отсутствующими строками - происходит в READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, предотвращается в SERIALIZABLE
...