Транзакция (ID процесса) была заблокирована для ресурсов блокировки с другим процессом и была выбрана в качестве жертвы тупика. Перезапустите транзакцию - PullRequest
17 голосов
/ 09 февраля 2012

У меня есть приложение C #, которое вставляет данные в таблицу SQL Server (2008) с помощью хранимой процедуры. Я использую многопоточность, чтобы сделать это. Хранимая процедура вызывается из потока. Теперь моя хранимая процедура использует «таблок» при вставке данных. При выполнении этого кода я получаю следующую ошибку: «Транзакция (идентификатор процесса) заблокирована для ресурсов блокировки другого процесса и выбрана в качестве жертвы тупика. Повторите транзакцию.»

Может кто-нибудь помочь мне с этим решением?

Ответы [ 5 ]

13 голосов
/ 09 февраля 2012

Это происходит, когда два процесса сервера Sql обращаются к одним и тем же ресурсам, но в другом порядке.Поэтому они оба ожидают другого процесса, который является тупиком.

Существует несколько способов предотвратить это, в том числе:

  • Избегайте ненужных блокировок.Проверьте уровень изоляции транзакции, требуемый для запроса, используйте with (nolock) подсказку блокировки для запросов, где это необходимо.
  • Убедитесь, что при получении блокировок вы берете блокировки для объектов в том же порядке в каждом запросе.

Например, если Proc1 блокирует table1 и затем table2, но Proc2 блокирует table2 и затем table1, проблема может возникнуть.Чтобы избежать этой проблемы, вы можете переписать любой процесс, чтобы получить блокировки в том же порядке.

6 голосов
/ 12 января 2015

Вы можете инкапсулировать свой запрос в блок TRY CATCH и отлавливать номера ошибок (связанных с блокировками)

  1. 1204
  2. 1205
  3. 1222

Затем вы можете автоматизировать повторные попытки, вплоть до определенного числа .. Таким образом, вы бы сделали что-то вроде следующего:

         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 .

0 голосов
/ 29 октября 2018

Вот решение от MSDN S Kumar Dubey

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/171d9fa9-0a39-48ce-bc38-35623e0c1075/how-can-i-release-lock-on-tables?forum=transactsql

Выполнить SP: SP_LOCK В результате вы получите SPID, DBID, OBJID, INDID, TYPERESOURCE, MODE, STATUS Теперь проверьте столбец состояния, если он показывает ожидание, а затем убейте этот SPID.Чтобы убить определенный SPID, выполните SP: Kill 65 (где 65 - SPID)

Похоже, вам нужно быть администратором SQL-сервера, чтобы решить эту проблему.

0 голосов
/ 09 августа 2018

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

  • Щелкните правой кнопкой мыши по таблице и выберите свойства.

  • Выберите параметр в правой панели в свойствах.

  • На вкладке блокировки «Разрешить блокировку страницы» установите «Ложь», а «Разрешить блокировку строки» должно быть «Истина», а затем нажмите «ОК».

  • Нажмите кнопку New Query и напишите команда «обновить имя таблицы статистики» и выполнить
  • Перестроить некластеризованный индекс.
0 голосов
/ 31 июля 2016

вы можете использовать из объекта 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 { }
    }
...