Такая схема может быть склонной к взаимоблокировке - обычно (не всегда) одно соединение вряд ли само блокируется, но множественные соединения, которые выполняют вставку и агрегирование по одной и той же таблице, с большой вероятностью могут заблокироваться. Это потому, что, хотя все действия в одной транзакции выглядят завершенными с точки зрения соединения, выполняющего работу - БД не будет блокировать транзакцию из «своих» записей - совокупные запросы из ДРУГИХ транзакций будут пытаться заблокировать весь стол или его большие части одновременно, и они зашли бы в тупик.
Read Uncommitted - , а не ваш друг в этом случае, потому что он в основном говорит "игнорировать блокировки", что в какой-то момент будет означать нарушение правил, которые вы установили для данных. И.Е. количество записей в таблице будет неточным, и вы будете действовать по этому неточному количеству. Ваш счет вернется 10 или 13, когда реальный ответ будет 11.
Лучший совет, который я имею, состоит в том, чтобы перестроить логику вставки так, чтобы вы уловили идею подсчета без буквального подсчета строк. Вы могли бы пойти пару направлений. У меня есть одна идея: буквально пронумеровать вставленные ваучеры последовательностью и наложить ограничение на саму последовательность.
- Создать таблицу последовательности со столбцами (я предполагаю) MallID, nextVoucher, maxVouchers
- Заполните эту таблицу маллидами, 1 и любым пределом для каждого торгового центра
- Измените логику вставки на этот псевдокод:
Begin Transaction
Sanity check the nextVoucher for Mall in the sequence table; if too many exist abort
If less than MaxVouchers for Mall then {
check, fetch, lock and increment nextVoucher
if increment was successful then use the value of nextVoucher to perform your insert.
Include it in the target table.
}
Error? Rollback
No Error? Commit
Такая таблица последовательностей вредит некоторым параллелизмам, но я думаю, что не так много, как постоянный подсчет строк в таблице. Обязательно перф тест.
Кроме того, [проверка, выборка, блокировка и приращение] важны - вам нужно только заблокировать строку в таблице последовательности, чтобы не допустить использования этим же значением другого соединения в течение доли секунды, прежде чем увеличивать его. Я знаю синтаксис SQL для этого, но боюсь, что я не эксперт по nHibernate.
Для ошибок чтения незафиксированных данных, проверьте это: http://sqlblog.com/blogs/merrill_aldrich/archive/2009/07/29/transaction-isolation-dirty-reads-deadlocks-demo.aspx (отказ от ответственности: Merrill Aldrich - это я: -)