Пессимистичная автономная блокировка с использованием Entity Framework - PullRequest
1 голос
/ 19 марта 2012

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

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

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

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

Ответы [ 3 ]

4 голосов
/ 19 марта 2012

Вы описываете пессимистическую блокировку, на самом деле нет споров по этому поводу.В превосходном учебном пособии по 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 В начале статьи есть пессимистическая глава.

3 голосов
/ 19 марта 2012

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

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

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

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

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

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

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

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, а столбец для строк контроля версий), и 2 потока одновременно вводят метод, второй будет получить исключение параллелизма. Но если у вас нет версий версий на уровне базы данных, я не думаю, что вам нужно делать какие-либо блокировки.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...