SqlException: тупик

У меня возникают эти два исключения, когда я пытаюсь получить данные из базы данных SQL на C #:

System.Data.SqlClient.SqlException: транзакция (идентификатор процесса 97) была заблокирована на ресурсах блокировки с другим процессом и была выбрана в качестве жертвы взаимоблокировки.

OR

System.Data.SqlClient.SqlException: транзакция (идентификатор процесса 62) была заблокирована на ресурсах блокировки с другим процессом и была выбрана жертвой взаимоблокировки.

OR

System.Data.SqlClient.SqlException: транзакция (идентификатор процесса 54) была заблокирована на ресурсах блокировки с другим процессом и была выбрана жертвой взаимоблокировки. Повторите транзакцию.

это код:

 using (SqlConnection con = new SqlConnection(datasource))
 {
    SqlCommand cmd = new SqlCommand("Select * from MyTable Where ID='1' ", con);
    cmd.CommandTimeout = 300;
    con.Open();
    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
    DataSet ds = new DataSet();
    adapter.Fill(ds);
    con.Close();
    return ds.Tables[0];
 }

Это происходило каждый раз.

Есть идеи, как это можно решить?


person Harold Sota    schedule 30.11.2010    source источник
comment
У вас было это исключение один раз или это происходит каждый раз, когда вы пытаетесь?   -  person Alexis Dufrenoy    schedule 30.11.2010
comment
Это случается каждый раз, когда я пытаюсь.   -  person Harold Sota    schedule 30.11.2010
comment
Мой запрос: выберите * из MyTable, где PRODUCT_ID = '1'   -  person Harold Sota    schedule 30.11.2010
comment
Одновременно должны выполняться другие запросы, поэтому он блокируется. Два или более запроса хотят получить доступ к одним и тем же данным. Нам нужно видеть все выполняемые запросы, а не только тот, который становится жертвой тупика.   -  person Colin Mackay    schedule 30.11.2010
comment
Вы не можете получить тупик из такого запроса. Требуется блокировка чтения для 1 строки в 1 таблице. Даже если бы другой процесс имел эту блокировку, он бы с радостью дождался, пока истечет время ожидания запроса. Чтобы попасть в тупик, обычно Process1 имеет блокировку A и ожидает блокировки B; в то время как Process2 имеет блокировку B и ожидает блокировки A. Должны быть задействованы некоторые другие запросы. Запустите Sql Server Profiler (msdn.microsoft.com/en-us/library/ ms187929.aspx) и отслеживайте, какие запросы выполняются в вашей базе данных.   -  person sheikhjabootie    schedule 30.11.2010
comment
Дополнительные ссылки для профилировщика и анализа взаимоблокировок: (1) support.microsoft. com / default.aspx? scid = kb; en-us; 832524 (2) msdn.microsoft.com/en-us/library/ms188246.aspx (3) msdn.microsoft.com/en-us/library/ms190465.aspx   -  person Marek Grzenkowicz    schedule 30.11.2010
comment
Некоторое время назад у Джеффа Этвуда было такое же исключение: Ужас программирования: тупик!. Его статья может помочь :-)   -  person Christophe Keller    schedule 30.11.2010


Ответы (3)


Не то чтобы это помогло решить проблему тупика, но вы должны избавляться от других ваших IDisposable объектов так же, как вы избавляетесь от своих SqlConnection как таковых:

    using (SqlConnection con = new SqlConnection(datasource))
    using (SqlCommand cmd = new SqlCommand("Select * from MyTable Where ID='1' ", con))
    {
        cmd.CommandTimeout = 300;
        con.Open();
        using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
        using (DataSet ds = new DataSet())
        {
            adapter.Fill(ds);
            return ds.Tables[0];
        }
    }

Вы можете избежать блокировки с помощью подсказки блокировки в своем запросе следующим образом:

Select * from MyTable with (nolock) Where ID='1'

Я хочу внести ясность, вы разрешаете чтение незафиксированных данных с помощью этого решения. Это риск в транзакционной системе. Прочтите этот ответ. Надеюсь это поможет.

person Jesse C. Slicer    schedule 30.11.2010

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

Прежде всего, запустите SQL Server Profiler и сообщите ему, чтобы он предоставил вам график тупиковых ситуаций. Выполнение этой трассировки покажет вам другой запрос, который конфликтует с вашим. Ваш запрос довольно прост, хотя я серьезно сомневаюсь, что у вас есть SELECT * запрос к таблице MyTable в вашей системе ...

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

Что еще вы можете сделать:

  • Ускорьте выполнение запросов, в том числе применив к ним правильные индексы.
  • Включите изоляцию моментальных снимков в базе данных и используйте SET TRANSACTION ISOLATION LEVEL SNAPSHOT в своих транзакциях, где это необходимо. Также включите зафиксированное чтение с управлением версиями строк. Во многих случаях этого достаточно для полного устранения большинства тупиковых ситуаций. Прочтите об уровнях изоляции транзакций. Поймите, что вы делаете.
person Dave Markle    schedule 30.11.2010

По сути, модель параллелизма SQL-сервера делает так, что вы никогда не сможете избежать этого исключения (например, полностью несвязанная транзакция может заблокировать друг друга, если они заблокируют одну и ту же страницу индекса или что-то еще). Лучшее, что вы можете сделать, - это сделать ваши транзакции короткими, чтобы снизить вероятность, и, если вы получите исключение, сделайте то, что оно говорит, и повторите транзакцию.

person erikkallen    schedule 30.11.2010
comment
Вы путаете понятия блокировки и взаимоблокировки. Совершенно неправда, что это исключение неизбежно. - person Dave Markle; 30.11.2010
comment
Нет. Если вы используете блокировку по умолчанию (иногда блокировку строк, иногда блокировку страницы), легко увидеть, что две несвязанные транзакции могут случайно заблокировать друг друга (по крайней мере, если они обновляют две таблицы внутри транзакции, и вы не используете подсказки, чтобы убедиться, что таблицы всегда читаются в одном и том же порядке). В случае с rowlock это менее очевидно, но здесь могут вас укусить индексы. - person erikkallen; 30.11.2010