#std661

Блокирующее чтение остатков в начале транзакции

1.1.

В ряде задач нужно выполнять блокирующее чтение итогов. Типовой случай - контроль остатков при проведении документа.

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

1.2.

Чтение остатков в этом сценарии должно быть блокирующим. Нужно запретить двум пользователям одновременно читать один и тот же остаток за период, счет и значения измерений.

Если чтение неблокирующее, два пользователя могут одновременно прочитать один и тот же остаток и независимо принять решение о списании.

Пример: оба пользователя видят 10 единиц остатка. Первый списывает 8, второй списывает 6. Итоговый остаток становится -4, что недопустимо для прикладной логики.

2.

Обычно контроль остатков делают запросом в модуле набора записей перед записью набора. У такого подхода есть две проблемы:

  • разработчик, как правило, не управляет порядком записи движений в разные регистры (платформа пишет их автоматически);
  • в части сценариев контроль не нужен, потому что движения заведомо не могут дать отрицательные остатки.

Если регистр с контролем записывается в начале транзакции, блокировка держится долго и мешает другим пользователям, пока пишутся остальные регистры.

Чтобы минимизировать влияние блокирующего чтения на производительность:

  • заранее анализируйте, какие остатки нужно контролировать и в каких случаях;
  • учитывайте сценарии, где контроль не нужен:
  • приходный документ может только увеличить остатки;
  • при перепроведении документ может списывать не больше, чем списал при первом проведении;
  • в начале транзакции (например, в ОбработкаПроведения) явно записывайте движения по регистрам, где контроль не нужен;
  • всегда используйте одинаковый порядок записи регистров (например, алфавитный);
  • для этих наборов записей ставьте БлокироватьДляИзменения = Ложь;
  • убедитесь, что у всех записываемых регистров накопления и бухгалтерии включен режим разделения итогов;
  • выполните остальную логику транзакции;
  • в самом конце транзакции явно запишите движения по регистрам, где контроль нужен;
  • для наборов записей этих регистров ставьте БлокироватьДляИзменения = Истина (это снижает риск взаимоблокировок);
  • после записи выполняйте запросы контроля остатков по отрицательным остаткам для нужного набора измерений;
  • если отрицательные остатки найдены, отменяйте транзакцию; если запрос пустой, фиксируйте.

Явную управляемую блокировку (ДЛЯ ИЗМЕНЕНИЯ в автоматическом режиме) в этом месте обычно не используют, потому что нужные остатки уже заблокированы записью на предыдущем шаге.

Пример

В процедуре ПередЗаписью модуля набора записей регистра бухгалтерии Хозрасчетный выполняется запрос:

Пример запроса

Запрос.Текст = "ВЫБРАТЬ
  |   СуммаОстаток,
  |   СуммаОстатокДт,
  |   СуммаОстатокКт
  |ИЗ
  |   РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, &Счет, , Организация = &Организация)";

Такой запрос читает и блокирует остатки по условию для всех пользовательских подключений. Ресурсы, созданные разделением итогов, фактически объединяются в один. В результате параллельность становится такой же, как если бы разделение итогов было отключено.

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

См. также
Источник

https://its.1c.ru/db/v8std#content:661