2013-10-10 6 views
3

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

public void PessimisticMyEntityHandler(Action<IEnumerable<MyEntity>> fieldUpdater, string sql, params object[] parameters) 
{ 
    using (var scope = new System.Transactions.TransactionScope()) 
    { 
     fieldUpdater(DbContext.Set<MyEntity>().SqlQuery(sql, parameters)); 
     scope.Complete(); 
    } 
} 

Вот мой тестовый код. В основном я только начинаю две задачи, и они оба пытаются заблокировать строку с идентификатором «1». Я предполагал, что вторая задача не сможет прочитать (и обновить) строку до тех пор, пока первая не завершит свое задание, но окно вывода показывает, что это действительно возможно.

Task.Factory.StartNew(() => 
{ 
     var dbRepo = new DatabaseRepository(); 
     dbRepo.PessimisticMyEntityHandler(myEntities => 
     { 
       Debug.WriteLine("entered into lock1"); 

       /* Modify some properties considering the current ones... */ 
       var myEntity = myEntities.First(); 
       Thread.Sleep(1500); 
       myEntity.MyEntityCode = "abcdefgh"; 
       dbRepo.Update<MyEntity>(myEntity); 

       Debug.WriteLine("leaving lock1"); 
    }, "SELECT * FROM MyEntities WITH (UPDLOCK, HOLDLOCK) WHERE Id = @param1", new SqlParameter("param1", 1)); 
}); 

Task.Factory.StartNew(() => 
{ 
     Thread.Sleep(500); 
     var dbRepo = new DatabaseRepository(); 
     dbRepo.PessimisticMyEntityHandler(myEntities => 
     { 
       Debug.WriteLine("entered into lock2"); 

       /* Modify some properties considering the current ones... */ 
       var myEntity = myEntities.First(); 
       myEntity.MyEntityCode = "xyz"; 
       dbRepo.Update<MyEntity>(myEntity); 

       Debug.WriteLine("leaving lock2"); 
    }, "SELECT * FROM MyEntities WITH (UPDLOCK, HOLDLOCK) WHERE Id = @param1", new SqlParameter("param1", 1)); 
}); 

окно Output:

entered into lock1 
entered into lock2 
leaving lock2 
leaving lock1 

ответ

6

То, что вы просите, включает в себя два основных явления в СУБД и особенно в SQL Server: Lock и Isolation Level. Я делаю все возможное, чтобы объяснить их в летописи.

Вы задали вопрос о Pessimistic Concurrency. Ответ: он еще не поддерживается в Entity Framework. Другими словами, с помощью обычного API EF вы не можете заблокировать таблицу или несколько строк для SELECT, как, например, Oracle через SELECT FOR UPDATE. Хотя вы можете это сделать, написав команду SQL, чтобы выбрать некоторые строки или всю таблицу с блокировкой Exclusive и сохранить эту блокировку до конца транзакции. Таким образом, другие потоки не только не могут обновлять выбранные строки, но также не могут их выбирать. Они блокируются, пока вы не отпустите блокировку. Это то, что я делаю в своих проектах, и хотя это как-то рискованно, все отлично.

Так в Summery: блокировки для выбора: NO на EF/Да нативным SQL

Замок для обновления:

При изменении строки в БД, измененные строки получить какой-то от lock. Вид блокировки определяется Isolation Level пробега Transaction. Значение по умолчанию Isolation Level в SQL Server равно Read Committed, что означает, что все строки, которые были изменены при текущем усилении транзакции Shared блокировки. Этот замок совместим с SELECT, но не с UPDATE или DELETE. Это означает, что при изменении строки в транзакции по умолчанию гарантируется, что другие параллельные потоки не могут вывести и изменить их до тех пор, пока вы не закончите транзакцию либо на COMMIT, либо на ROLLBACK.

.

Update:

Таблица намеков UPDLOCK and HOLDLOCK могут быть проигнорированы оптимизатором запросов или других СУБД модулей, так как они просто намек :-). Единственная комбинация табличных подсказок, которая обязательно соблюдается, - (XLOCK, PAGLOCK).

Example: SELECT * FROM MyTable WITH (XLOCK, PAGLOCK) 

Как я уже говорил, ручное блокирование является рискованным. Используйте его с максимальным уровнем рассмотрения.

+0

Спасибо за ответ, но, как вы можете видеть из моего кода, я уже знаю это (явно не все). Я просто не понимаю, почему мой код не работает. – laszlokiss88

+0

Не могли бы вы привести пример кода, чтобы показать, как вы это делаете в своих проектах? – laszlokiss88

+0

@ laszlokiss88 Я обновил ответ. Так понятно? – Alireza

Смежные вопросы