В современной разработке на платформе 1С:Предприятие 8.3 часто возникает вопрос: почему общепринятым стандартом стало сначала записывать данные в регистр накопления, а уже затем проверять наличие отрицательных остатков? На первый взгляд, это кажется нелогичным: зачем совершать лишнее действие записи, если товара может не хватить? Однако за этим подходом, известным как «новая методика проведения», стоят серьезные требования к производительности, масштабируемости и корректности работы в многопользовательской среде. Разберем эту тему подробно.
Проанализируем путь развития механизмов проведения. В старых типовых конфигурациях (например, «Управление производственным предприятием» или «Управление торговлей 10.3») использовалась так называемая старая методика. Ее суть заключалась в том, что программа сначала рассчитывала «прогнозный» остаток (текущий остаток минус то, что мы хотим списать) и, если результат был положительным, записывала движения.
В современных решениях, таких как 1С:ERP или Управление торговлей 11, применяется новая методика. Здесь мы сначала фиксируем факт списания в базе данных (внутри транзакции), а потом одним простым запросом проверяем — не ушел ли остаток в «минус». Если ушел — транзакция отменяется (откатывается).
Рассмотрим, как видит наши действия сервер базы данных. При использовании старой методики нам нужно выполнить запрос, в котором происходит соединение временной таблицы (товары из документа) с виртуальной таблицей остатков. Для СУБД (например, MS SQL Server или PostgreSQL) это сложный запрос с точки зрения построения плана выполнения. Необходимо сопоставить данные в памяти с данными на диске, учитывая множество условий.
При использовании новой методики порядок действий меняется:
Запрос в новой методике максимально прост: ВЫБРАТЬ ... ИЗ Регистр.Остатки ГДЕ КоличествоОстаток < 0. СУБД выполняет такой запрос молниеносно, так как ей не нужно делать сложные соединения (Join) с данными документа — данные уже находятся «внутри» регистра (хоть и не зафиксированы окончательно).
Разберем ситуацию, когда несколько пользователей одновременно проводят документы по одному и тому же товару. Выясним, почему это критично. В системе 1С используется механизм управляемых блокировок. Чтобы данные остатков не изменились другими пользователями в процессе нашего проведения, мы должны «заблокировать» нужные нам записи.
В новой методике блокировка данных происходит в момент записи движений. Это позволяет минимизировать время, в течение которого другие пользователи ждут доступа к этим ресурсам. Проанализируем цепочку событий:
Если мы сначала проверим, а потом запишем, возникает риск «фантомных остатков»: два пользователя одновременно увидели, что на складе есть 1 шт. товара, оба решили, что им хватает, и оба записали списание. В итоге остаток станет -1. Новая методика исключает это на уровне архитектуры: запись происходит раньше проверки, и за счет транзакционной блокировки второй пользователь просто не сможет прочитать остаток, пока первый не завершит (или не отменит) свою операцию.
Посмотрим на пример кода, предоставленный в вопросе. В старой методике программисту пришлось бы вручную вычитать количество из документа из полученного остатка. Это лишние арифметические операции в коде 1С, которые при больших объемах данных замедляют работу.
В новой методике мы делегируем расчет платформе и СУБД. Нам не нужно знать, сколько будет. Нам нужно знать, что стало. Если КоличествоОстаток < 0, значит, мы попытались списать больше, чем было.
Пример запроса для контроля остатков после записи:
Запрос3 = Новый Запрос;
Запрос3.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос3.Текст = "ВЫБРАТЬ
| ОстаткиМатериаловОстатки.Материал,
| ОстаткиМатериаловОстатки.КоличествоОстаток
|ИЗ
| РегистрНакопления.ОстаткиМатериалов.Остатки( ,
| Материал В (ВЫБРАТЬ НоменклатураДокумента.Номенклатура ИЗ НоменклатураДокумента)
| И Склад = &Склад) КАК ОстаткиМатериаловОстатки
|ГДЕ
| ОстаткиМатериаловОстатки.КоличествоОстаток < 0";
Важно понимать: вызов метода Движения.Записать() не означает, что данные «намертво» впечатались в базу. Весь код процедуры ОбработкаПроведения выполняется внутри одной транзакции. Если в конце процедуры мы установим Отказ = Истина, платформа даст команду СУБД Rollback (Откат). Все записи, сделанные в регистр в ходе этой процедуры, будут физически удалены из таблиц базы данных так, будто их никогда и не было.
Несмотря на преимущества новой методики, существуют исключения. Рассмотрим ситуации, когда старый подход может быть оправдан:
Подведем итог нашему анализу. Использование записи перед проверкой в ОбработкаПроведения — это не ошибка, а требование современной архитектуры 1С. Это позволяет:
Для успешной сдачи экзаменов «1С:Специалист» и разработки высоконагруженных систем крайне важно придерживаться именно новой методики проведения везде, где это позволяет бизнес-логика.