Транзакция (идентификатор процесса) зашла в тупик на ресурсах блокировки с другим процессом и была выбрана в качестве жертвы взаимоблокировки. Повторить транзакцию
У меня есть приложение С#, которое вставляет данные в таблицу SQL Server (2008), используя хранимую процедуру. Для этого я использую многопоточность. Хранимая процедура вызывается изнутри потока.
Теперь моя хранимая процедура использует "tablock" при вставке данных.
Выполняя этот код, я получаю следующую ошибку:
"Транзакция (идентификатор процесса) зашла в тупик на ресурсах блокировки с другим процессом и была выбрана в качестве жертвы взаимоблокировки. Перезапустите транзакцию".
Кто-нибудь может помочь мне с любым решением?
Ответы
Ответ 1
Это происходит, когда два Sql-сервера обращаются к тем же ресурсам, но в другом порядке. Поэтому они в конечном итоге ожидают другого процесса, который является тупиком.
Существует несколько способов предотвратить его, в том числе:
- Избегайте ненужных блокировок. Просмотрите уровень изоляции транзакций, необходимый для запроса, используйте
with (nolock)
подсказку для запросов, где это необходимо.
- Убедитесь, что при выполнении блокировок вы берете блокировки объектов в том же порядке в каждом запросе.
например. если Proc1 блокирует таблицу1, а затем таблицу2, но Proc2 блокирует таблицу2, а затем таблицу1, проблема может возникнуть. Вы можете переписать либо proc для блокировки в том же порядке, чтобы избежать этой проблемы.
Ответ 2
Вы можете инкапсулировать свой запрос в блок TRY CATCH и улавливать номера ошибок (связанные с блокировками)
Затем вы можете автоматизировать повторные попытки, вплоть до определенного числа. Таким образом, вы сделали бы что-то вроде следующего:
DECLARE @RetryNo Int = 1
,@RetryMaxNo Int = 5;
WHILE @RetryNo < @RetryMaxNo
BEGIN
BEGIN TRY
-- put your query that generates locks here....
SELECT @RetryNo = @RetryMaxNo;
END TRY
BEGIN CATCH
IF ERROR_NUMBER() IN (1204, 1205, 1222)
BEGIN
SET @RetryNo += 1;
-- it will wait for 10 seconds to do another attempt
WAITFOR DELAY '00:00:10';
END
ELSE
THROW;
END CATCH
END
Вы также можете использовать табличные подсказки, такие как UPDLOCK.
Ответ 3
вы можете использовать из объекта Lock
static object _lock = new object();
public static void _main()
{
lock (_lock)
{
_bulkcopy(myData);
}
}
public static void _bulkcopy(DataTable dt)
{
try
{
using (var connection = new SqlConnection(ConfigurationSettings.AppSettings.Get("DBConnection")))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BatchSize = 100;
bulkCopy.DestinationTableName = "dbo.MyTable";
try
{
bulkCopy.WriteToServer(dt);
}
catch (Exception)
{
transaction.Rollback();
connection.Close();
}
}
transaction.Commit();
}
}
catch { }
}