2012-03-19 2 views
1

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

Для этого я пришел к следующему: таблица будет содержать флаг, который указывает, будет ли элемент проверен для редактирования, и «время окончания», в то время как этот флаг действителен. Значение по умолчанию для него равно 3 минутам, если в это время не происходит взаимодействия с пользователем, флаг может быть проигнорирован в следующий раз, когда пользователь попытается открыть тот же элемент.

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

Итак, вопрос. :) Если пользователь открывает элемент в режиме редактирования, сначала я должен прочитать значения времени & для элемента времени, и если я нахожу их действительными (флаг не установлен или не установлен, но не действителен из-за времени), и я должны обновить их новыми значениями. Какой уровень транзакций я должен использовать для этого в EF, если таковой имеется? Или я должен писать хранимые процедуры для обработки обновления & в транзакции? Если да, какой метод блокировки я должен использовать?

ответ

3

Оптимистическая блокировка в этом случае по-прежнему в порядке.Вы можете использовать timestamp/rowversion и ваш флаг вместе. Флаг будет использоваться для обработки вашей прикладной логики - только один пользователь может редактировать запись, а timestamp будет использоваться, чтобы избежать состояния гонки при установке флага, потому что только один поток сможет прочитать запись и записать ее обратно. Если какой-либо другой поток пытается прочитать запись одновременно и сохраняет ее после первого потока, она получит исключение параллелизма.

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

1

Ответ ниже не является хорошим способом реализации пессимистического параллелизма. Вы не должны реализовывать это на уровне приложения. Для РСУБД есть лучшие инструменты для этого.

Если вы блокируете строку в db, это по определению pessimistic.

Поскольку вы контролируете пессимистический параллелизм на уровне приложения, я не думаю, что это имеет значение, для которого используется область транзакций EF. EF автоматически запускает транзакцию уровня db, когда вы SaveChanges.

Чтобы предотвратить несколько потоков от выполнения блокировки/разблокировки из вашего приложения, вы можете заблокировать фрагмент кода, который запрашивает & обновления, как так:

public static object _lock = new object(); 

public class MyClassThatManagesConcurrency 
{ 
    public void MyMethodThatManagesConcurrency() 
    { 
     lock(_lock) 
     { 
      // query for the data 
      // determine if item should be unlocked 
      // dbContext.SaveChanges(); 
     } 
    } 
} 

С выше, нет 2 нити никогда не будет выполнять код внутри раздела lock в то же время. Однако я не уверен, почему это необходимо. Если все, что вы делаете, это чтение объекта и его разблокировка по истечении времени, а 2 потока одновременно вводят метод, в любом случае элемент будет разблокирован.

С другой стороны, если ваш дб строка для этого объекта имеет timestamp столбец (не datetime столбец, но в columng для управления версиями строк), и 2 нити ввести метод в то же самое время, второй получит параллелизм исключение. Но если у вас нет версий строк на уровне db, я не думаю, что вам нужно делать блокировку.

Ответить на комментарий

Хорошо я получаю сейчас, вы правы. Но вы по-прежнему блокируете уровень приложения, а это означает, что не имеет значения, какую именно транзакцию eb выбирает. Чтобы заблокировать 2 пользователя от одного и того же объекта, используйте блокировку блокировки C#, указанную выше.

+0

Временная метка была бы в порядке, если бы я использовал оптимистичную блокировку, насколько я знаю. В этом случае я мог бы использовать встроенные функции EF для обработки параллельных обновлений. Однако я хотел бы предотвратить ситуацию, когда два человека начнут работать над одним и тем же случаем. (потому что в этом случае они оба найдут решение, начнут писать ответ (из приложения), а после работы, которую они получат boo, кто-то уже решил это.) Что касается имени управления параллелизмом, я цитировал это из EF4 в книге действий. :) (решение на полпути: пессимистический/оптимистический контроль параллелизма) – norbip

+0

Вы описываете пессимистическую блокировку, на самом деле нет дебатов. Вы не должны реализовывать блокировку самостоятельно, пусть это делает СУБД. – RickAndMSFT

4

Вы описываете пессимистическую блокировку, на самом деле нет дебатов. Есть подробные инструкции о том, что вы хотите сделать в отличном учебнике MVC/EF. http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application В начале есть глава о пессимистике.

+0

Я вижу. Но в этом случае «застрявшие» замки должны быть очищены механизмом через какое-то время, не так ли? Кроме того, есть ли какие-либо проблемы с описанным мной решением, кроме того, что блокировка не должна выполняться на уровне приложения? Я рассматриваю свое решение как более эластичное по сравнению с блокировками БД (хотя у меня нет таких знаний в замках БД, я полагаю, что описанное мной поведение также можно было сделать, используя их). – norbip

+1

+1, я бросаю свой вес за опыт Рика. Не похоже было сделать пессимистическую блокировку из приложения. Кроме того, решение, которое я опубликовал, может завершиться неудачно, если у вас было более статичного «MyClassThatManagesConcurrency» (в другом загрузчике классов на другой машине). – danludwig

+0

Я только что прочитал эту статью, и это очень хорошо отражает то, что я хотел бы достичь: http://www.ibm.com/developerworks/websphere/techjournal/0603_ilechko/0603_ilechko.html#sec4 (секция блокировки пессимистического сеанса). Что касается моего вопроса - исправьте меня, если я ошибаюсь - его можно решить, применив условия гонки с одним из подходов, предложенным в ответе Ладислава. – norbip

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