Почему следующий SQL Server вставляет взаимоблокировку при запуске в транзакции?

В настоящее время я вставляю запись в таблицу SQL Server, а затем выбираю идентификатор автоинкремента следующим образом:

(@p0 int,@p1 nvarchar(8))INSERT INTO [dbo].[Tag]([Some_Int], [Tag])
VALUES (@p0, @p1)

SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value] 

(Это было создано с использованием Linq-to-SQL). По какой-то причине, когда я запускаю этот код внутри транзакции с использованием объекта TransactionScope с уровнем изоляции Serializable, SQL Server выдает ошибку взаимоблокировки. Я проанализировал события графа взаимоблокировок и обнаружил, что каждый из двух задействованных процессов ожидал другого выполнения операции преобразования, поскольку я понимаю следующую информацию:

<resource-list>
   <keylock hobtid="72057594101170176" dbid="5" objectname="foo.dbo.Tag" indexname="PK_Tag_1" id="lockb77cdc0" mode="RangeS-S" associatedObjectId="72057594101170176">
    <owner-list>
     <owner id="processc9be40" mode="RangeS-S"/>
    </owner-list>
    <waiter-list>
     <waiter id="processc9ae38" mode="RangeI-N" requestType="convert"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594101170176" dbid="5" objectname="foo.dbo.Tag" indexname="PK_Tag_1" id="lockb77cdc0" mode="RangeS-S" associatedObjectId="72057594101170176">
    <owner-list>
     <owner id="processc9ae38" mode="RangeS-S"/>
    </owner-list>
    <waiter-list>
     <waiter id="processc9be40" mode="RangeI-N" requestType="convert"/>
    </waiter-list>
   </keylock>
  </resource-list>

Насколько я понимаю, объем транзакции не позволит второму процессу выполнить вставку до тех пор, пока первый не завершит как вставку, так и выбор идентификатора. Однако, похоже, это не так. Может ли кто-нибудь пролить свет на лучший подход к достижению того, что мне нужно, поточно-ориентированным способом?

- Обновлено -

Просто отметить; Я на 99% уверен, что соединение не используется совместно двумя процессами, поскольку каждый из них создает новый DataContext для связи с базой данных.

- Снова обновлено -

Ремус Русану указал, что некоторая упущенная информация была связана с проблемой, я попытался упростить сценарий на основе отчета о графике тупиков, но я расширил объяснение здесь. Перед тем, как сделать вставку, я выполняю запрос «существует» для рассматриваемой таблицы, чтобы определить, существует ли уже тег. Если это так, я завершаю транзакцию. Если нет, вставка должна выполняться, а затем я выполняю обновление, не показанное здесь, для таблицы, которая имеет Some_Int в качестве первичного ключа, хотя обновление предназначено исключительно для последнего измененного значения. Также может быть важно, чтобы таблица тегов имела кластерный индекс, состоящий из идентификатора auto inc ID и Some_Int. Я не думал, что эта последняя информация имеет отношение к делу, поскольку я безуспешно пытался изменить таблицу, чтобы в качестве первичного ключа / кластеризованного индекса использовалось только поле auto inc.

Спасибо.


person LaserJesus    schedule 15.06.2009    source источник
comment
Чертовски хороший вопрос! Я хочу увидеть ответ.   -  person Chris    schedule 15.06.2009


Ответы (3)


Рассматриваемое 'преобразование' - это 'преобразование блокировки' из RangeS-S в RangeI- N, никак не относящийся к функции CONVERT. Тот факт, что у вас есть блокировки RangeS-S, уже помещенные в индекс PK_Tag_1, указывает на то, что вы делаете нечто большее, чем просто INSERT. Выполняется ли ваша транзакция, случайно, сначала, чтобы увидеть, существует ли новая запись, прежде чем пытаться вставить?

person Remus Rusanu    schedule 15.06.2009
comment
Я обновил вопрос, чтобы более полно отразить ситуацию - person LaserJesus; 16.06.2009
comment
Я изменил уровень изоляции на моментальный снимок, что, похоже, облегчило мои проблемы с тупиком. Спасибо за вашу помощь :) - person LaserJesus; 16.06.2009
comment
Кроме того, я понимаю, что изоляция моментального снимка не предотвратит случай, когда повторяющиеся теги связаны с одним и тем же объектом. Для этого я создам уникальное ограничение ключа и аккуратно устраню потенциальную ошибку. - person LaserJesus; 16.06.2009

Проверьте уровень изоляции, который используется в вашем запросе. Обратите внимание, что TransactionScope по умолчанию использует уровень изоляции Serializable (http://msdn.microsoft.com/en-us/library/ms172152.aspx). Попробуйте изменить уровень изоляции вашей транзакции на Read Commited.

person ckaut    schedule 31.01.2010

Вам вообще не нужна транзакция. Функция scope_identity() вернет идентификатор, последний раз созданный в той же области, поэтому нет проблем, если другая вставка будет выполнена до того, как вы получите идентификатор, так как это находится в другой области.

person Guffa    schedule 15.06.2009
comment
Объем транзакции таков, что я могу откатить изменения, если что-то пойдет не так в другом месте или, по крайней мере, когда закончится uni test. - person LaserJesus; 15.06.2009
comment
@downvoter: Почему голос против? Если вы не скажете то, что считаете неправильным, это никоим образом не улучшит ответ. - person Guffa; 02.11.2010