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

У меня есть приложение С#, которое вставляет данные в таблицу 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 { }
    }