Предотвращение состояния гонки во время нескольких одновременных запросов в Asp.Net MVC и EF - PullRequest
0 голосов
/ 11 октября 2018

У меня есть один метод контроллера, который создает новый заказ в базе данных с инкрементным пользовательским идентификатором заказа (т. Е. ABC000005)

В таблице заказов есть поля ниже

Id (PK)
Name
CustomOrderId
DateTime

Для реализации этого у меня естьнаписанный метод, подобный приведенному ниже

var lastOrder = _dbContext.Order.OrderByDescending(x=>x.DateTime).First();
var lastOrderCustomId = lastOrder.CustomOrderId;

// Some other code which takes around 2 seconds

var newOrderId = //Calculation to increment custom order id (i.e. ABC000005 to ABC000006)
var newOrder = new Order();
newOrder.Name = "abc";
newOrder.DateTime = DateTime.UtcNow;
newOrder.CustomOrderId = newOrderId;
_dbContext.Order.Add(newOrder);
_dbContext.SaveChanges();

Приведенный выше код хорошо работает при последовательных запросах к серверу, но при одновременных запросах 2 запроса будут извлекать одинаковые CustomOrderId из базы данных и создавать два новых идентичных CustomOrderIdзначения в базе данных.

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

Есть ли какое-либо иное решение этой конкретной проблемы?

1 Ответ

0 голосов
/ 11 октября 2018

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

  1. Когда вы получаете запрос на создание нового заказа, проверьте в кеше, присутствует ли latest_custom_order_id.
  2. Если его нетзатем выберите предыдущий пользовательский идентификатор заказа и вычислите следующий идентификатор заказа.
  3. Если имеется, то рассчитайте идентификатор заказа клиента, используя этот идентификатор заказа.
  4. Обновите значение ключа кэша, указав последний идентификатор заказа.например."latest_custom_order_id":"ABC0004"
  5. Сохранить заказ
...