2010-11-30 3 views
8

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

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

ИЛИ

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

ИЛИ

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]; 
       } 

Эти hapened время Эври.

Любые идеи, как это можно решить?

+2

У вас есть это исключение один раз или это происходит каждый раз, когда вы пытаетесь? – 2010-11-30 10:20:59

+3

Не могли бы вы показать свой запрос? – 2010-11-30 10:21:42

ответ

7

Не то, что это собирается помочь проблеме тупиковой, но вы должны распоряжаться другие ваши 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' 

Надеюсь, что это поможет.

3

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

16

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

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

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

Другие вещи, которые вы можете сделать:

  • скорость до ваших запросов, среди прочего, применяя правильные индексы для них.
  • Включите изоляцию моментальных снимков в базе данных и используйте SET TRANSACTION ISOLATION LEVEL SNAPSHOT в своих транзакциях, где это необходимо. Также включите read committed with row-versioning. Во многих случаях этого достаточно, чтобы полностью исключить большинство взаимоблокировок. Читайте об уровнях изоляции транзакций. Understand что вы делаете.