Entity Framework Dead Lock Victim для операторов только для чтения - PullRequest
5 голосов
/ 23 марта 2012

У меня есть служба OData (Служба данных WCF с использованием Entity Framework).

Все, что делает эта служба - это выбор данных.(Не пишет НИКОГДА.)

Когда я запускаю свои запросы OData, я иногда получаю сообщения об ошибках вроде этого:

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

Может ли оператор select быть жертвой мертвой блокировки?Или Entity Framework пытается заблокировать вещи, которые он не должен блокировать?

Если он блокируется там, где его не должно быть, есть ли способ сообщить Entity Framework НИКОГДА не блокировать?(Для этой службы она всегда и навсегда будет доступна только для чтения.)

Ответы [ 2 ]

11 голосов
/ 23 марта 2012

Не просто используйте ReadUncommitted или NOLOCK. Они будут: а) легко возвращать противоречивые результаты и б) вызывать ложные ошибки из-за «перемещения данных». Не надо!

Намного лучше было бы включить изоляцию моментальных снимков с помощью следующего SQL:

ALTER DATABASE [DB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
ALTER DATABASE [DB] SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE [DB] SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE [DB] SET MULTI_USER

Это приведет к тому, что транзакции чтения не будут блокироваться и не будут блокироваться существующими блокировками. Это, вероятно, решит вашу проблему.

1 голос
/ 23 марта 2012

Вы не упомянули, какая база данных находилась за вашей службой OData, так что это может быть неактуально. В SQL Server вы можете привязать свои операторы SELECT WITH nolock, чтобы запретить выбор блокировать таблицу. Наличие этого говорит мне, что SELECTS определенно являются кандидатами на проблемы с блокировкой.

К сожалению, в EF нет способа указать WITH nolock в ваших запросах. Самое близкое, что я смог найти, - это обернуть ваше соединение в транзакцию и установить уровень изоляции для чтения некоммутированных (как указано в ответе на вопрос, который я связал в комментариях). *

Вот пример кода из ответа на связанный вопрос, чтобы показать, как вы это сделаете:

//declare the transaction options
var transactionOptions = new System.Transactions.TransactionOptions();
//set it to read uncommited
transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
//create the transaction scope, passing our options in
using (var transactionScope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
{
    //declare our context
    using (var context = new MyEntityConnection())
    {
        //any reads we do here will also read uncomitted data
        //...
        //...
    }
    //don't forget to complete the transaction scope
    transactionScope.Complete();
}
...