Предположим, мне нужно выбрать максимальное значение в качестве номера заказа. Таким образом, я выберу MAX(число), назначу номер заказу и сохраню изменения в базе данных. Тем не менее, как я могу помешать другим возиться с номером? Подойдут ли транзакции? Что-то вроде:
ordersRepository.StartTransaction();
order.Number = ordersRepository.GetMaxNumber() + 1;
ordersRepository.Commit();
Будет ли приведенный выше код "блокировки" изменен, чтобы номера заказов читались/записывались только одним клиентом БД? Учитывая, что транзакции являются простыми NHibernate, а GetMaxNumber просто выполняет SELECT MAX(Number) FROM Orders.
Ответ 1 · рейтинг 1 · Vijay Patel
Использование ITransaction с IsolationLevel.Serializable должно помочь. Однако будьте осторожны с разногласиями за столом. Если у вас есть высокочастотные обновления на столе, все может сильно замедлиться. Возможно, вы захотите профилировать попадание в базу данных при использовании GetMaxNumber().
Мне пришлось сделать что-то подобное, чтобы сгенерировать пользовательские идентификаторы для высокой степени параллелизма. Мое решение переместило генерацию идентификатора в базу данных и использовало отдельную таблицу Counter для хранения максимальных значений.
Использование отдельной таблицы Counter имеет несколько плюсов:
- Удаляет конкуренцию за таблицу
Order
- Обычно это быстрее
- Если он достаточно мал, его можно закрепить в памяти.
Я также использовал хранимую процедуру для возврата следующего доступного идентификатора:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
UPDATE [COUNTER] SET Value = Value + 1 WHERE COUNTER_ID = @counterId
COMMIT TRAN
RETURN [NEW_VALUE]
Надеюсь, это поможет.