Блокирующее чтение остатков в начале транзакции
#std661
Область применения: управляемое приложение, мобильное приложение, обычное приложение.
1.1. В ряде случаев необходимо выполнять блокирующее чтение итогов. Примером такой задачи является контроль остатков при проведении документа. Если в результате проведения документа остатки станут отрицательными, то транзакция должна быть отменена (проводить такой документ нельзя).
1.2. Операция чтения остатков должна быть блокирующей, то есть необходимо запретить двум пользователям одновременно читать один и тот же остаток за период, счет и значение измерения.
Если чтение будет неблокирующим, то возможна ситуация, при которой два пользователя одновременно прочитают один и тот же остаток (например 10 единиц) и примут решение о возможности списания части этого остатка. Если сумма списаний двух пользователей будет больше 10, то в итоге остаток получится отрицательным.
Например, первый пользователь спишет 8 единиц (8 меньше 10, следовательно операция разрешена), а второй пользователь спишет 6 единиц (на таком же основании). Результатом будет -4 единицы остатка, что недопустимо с точки зрения прикладной логики системы.
2. Обычно, для контроля остатков используется запрос в модуле набора записей регистра, который идет перед записью набора. При этом возможны следующие проблемы:
-
Разработчик, как правило, не контролирует порядок записи движений в разные регистры - запись обычно осуществляется автоматически платформой 1С:Предприятия. Запрос контроля остатков реализуется в модуле набора записей и вызывается при записи движений регистра. Если этот регистр будет записываться в начале транзакции (например, первым), то установленная блокировка будет мешать работе других пользователей в течение длительного периода времени (пока будут записываться все остальные регистры), и ее влияние на производительность системы может оказаться неоправданно большим.
-
В некоторых случаях, возможно, нет необходимости в контроле остатков, поскольку записываемые движения заведомо не могут привести к получению отрицательных остатков.
Для того чтобы минимизировать влияние блокирующего чтения остатков на производительность системы, необходимо:
-
Проанализировать, какие именно остатки нуждаются в блокирующем чтении и при каких обстоятельствах. Например, контроль остатков не требуется при проведении приходного документа, поскольку он может только увеличить остатки. Так же не требуется контролировать остатки при перепроведении документа, который списывает в этот раз не больше остатков чем при первом проведении (этот контроль уже проводился). И так далее.
-
В начале транзакции (например, в обработчике ОбработкаПроведения документа) в явном виде записать движения по всем регистрам, которые в данном случае не требуют контроля остатков. Следует всегда придерживаться одинакового порядка записи регистров (например, алфавитного). Необходимо обратить внимание на то, что у всех записываемых регистров накопления и бухгалтерии должен быть включен разделитель итогов, а у наборов записей свойство БлокироватьДляИзменения должна быть установлена в значение Ложь.
-
Выполнить все остальные действия, которые должны быть выполнены в рамках этой транзакции.
-
В самом конце транзакции в явном виде записать движения по тем регистрам, которые требуют контроля остатков. Для наборов записей этих регистров следует установить опцию БлокироватьДляИзменения в значение Истина. Это необходимо для предотвращения взаимоблокировки. В этом случае при записи набора записей будет установлена блокировка остатков регистра по данному набору значений измерений.
-
Для каждого регистра выполнить запрос контроля остатков. Следует обратить внимание, что в данном случае нет необходимости использовать явную управляемую блокировку (опцию ДЛЯ ИЗМЕНЕНИЯ - в автоматическом режиме), поскольку проверяемые остатки уже заблокированы их записью на предыдущем шаге. Запрос должен считывать только отрицательные остатки по заданному набору значений измерений. Если такие записи имеются, то транзакция должна быть отменена. Если запрос вернул пустой результат, то транзакция должна быть зафиксирована.
Пример
В процедуре ПередЗаписью модуля набора записей регистра бухгалтерии Хозрасчетный выполняется следующий запрос:
Запрос.Текст = "ВЫБРАТЬ
| СуммаОстаток,
| СуммаОстатокДт,
| СуммаОстатокКт
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, &Счет, , Организация = &Организация)";
При выполнении этого запроса будут прочитаны (и заблокированы от записи) остатки по указанному условию для всех пользовательских подключений. То есть, разные ресурсы (созданные режимом разделения итогов) будут как бы объединены в один. По этой причине параллельность останется такой же, как если бы режим разделения итогов не был включен.
Для того чтобы минимизировать влияние этой блокировки на общую производительность системы, рекомендуется перенести ее как можно ближе к концу транзакции. Например, можно вынести эту проверку в модуль документа в обработчик события ПриПроведении после записи (в явном виде) всех движений по всем регистрам.
См. также