Как устранить конфликт блокировок при открытии формы выбора в процессе проведения документа

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В практике разработки на платформе «1С:Предприятие» (особенно в конфигурациях на обычных формах, таких как УТ 10.3) часто встречается ситуация, когда программисту необходимо получить от пользователя дополнительные данные непосредственно в момент проведения документа. Самым простым, но в корне неверным решением кажется вызов диалогового окна или формы выбора прямо в процедуре ПередЗаписью модуля объекта. В данной статье мы разберем, почему это приводит к остановке работы всей базы, и как правильно перестроить логику приложения, чтобы избежать конфликтов блокировок.

Почему блокируется вся база данных: анализ механизма транзакций

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

Дело в том, что в 1С процедура ПередЗаписью модуля объекта всегда выполняется внутри транзакции базы данных. Транзакция — это неделимая последовательность операций. Как только она началась, система накладывает блокировки на таблицы, к которым обращается документ. В режиме автоматических блокировок (который чаще всего используется в старых конфигурациях) СУБД использует уровень изоляции SERIALIZABLE.

Рассмотрим цепочку событий:

  1. Пользователь нажимает «ОК» в документе.
  2. Начинается транзакция записи.
  3. Выполняется код в модуле объекта ПередЗаписью.
  4. Открывается форма выбора. Транзакция «зависает» в ожидании ответа пользователя.
  5. СУБД удерживает исключительные блокировки на таблицы документа, регистров и, что самое критичное, на системные таблицы (например, таблицу номеров или регистрации изменений).
  6. Другие пользователи пытаются совершить любое действие, требующее записи в те же системные таблицы (например, создание нового справочника), и попадают в очередь ожидания.

Если ожидание длится долго, происходит эскалация блокировок: вместо отдельных строк СУБД блокирует целые таблицы. Именно поэтому «стоит» вся база.

Различия между ПередЗаписью в модуле формы и в модуле объекта

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

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

В модуле объекта событие ПередЗаписью срабатывает после начала транзакции. Здесь интерактив строго запрещен. Более того, при программной записи документа (например, групповое перепроведение или обмен данными) форма просто не сможет открыться, что приведет к ошибке выполнения.

Решение 1: Перенос интерактивной логики в модуль формы

Это самый правильный и рекомендуемый путь. Мы должны собрать все необходимые данные до того, как система начнет блокировать таблицы БД. Рассмотрим пример кода для модуля формы:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Проверяем, что это именно проведение документа пользователем
    Если РежимПроведения = РежимПроведенияДокумента.Проведение Тогда
        
        // Если параметры оплаты еще не заполнены в реквизитах
        Если НЕ ЗначениеЗаполнено(Объект.ВариантОплаты) Тогда
            
            // Открываем форму выбора (не блокируя транзакцию!)
            ВыбранныйВариант = ОткрытьФормуМодально("Справочник.ВариантыОплаты.ФормаВыбора");
            
            Если ВыбранныйВариант = Неопределено Тогда
                // Если пользователь передумал выбирать - отменяем запись
                Отказ = Истина;
                Возврат;
            Иначе
                // Записываем значение в реквизит объекта формы
                Объект.ВариантОплаты = ВыбранныйВариант;
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЕсли;

КонецПроцедуры

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

Решение 2: Использование признака готовности документа

Иногда логика требует, чтобы документ сначала был записан, а потом проведен с особыми параметрами. В этом случае можно использовать механизм «статусов» или вспомогательных реквизитов. Разберем этот алгоритм по шагам:

  1. Добавьте в документ реквизит ПараметрыЗаполнены (тип Булево).
  2. В модуле объекта в процедуре ОбработкаПроведения добавьте проверку:
    
    Если НЕ ПараметрыЗаполнены Тогда
        Сообщить("Документ не может быть проведен без выбора параметров оплаты!");
        Отказ = Истина;
        Возврат;
    КонецЕсли;
    
  3. На форму документа вынесите кнопку «Заполнить параметры и провести». По нажатию на эту кнопку сначала открывайте форму выбора, заполняйте реквизиты, устанавливайте ПараметрыЗаполнены = Истина, и только затем вызывайте метод Записать(РежимЗаписиДокумента.Проведение).

Решение 3: Обработка группового проведения

Проанализируем ситуацию, когда документы проводятся обработкой «Групповое проведение». В этом случае формы не открываются, и код в модуле формы не исполняется. Чтобы система не «упала», в модуле объекта необходимо предусмотреть значения по умолчанию или алгоритмы автоматического определения параметров.

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

Особенности перехода на управляемые блокировки

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

Однако, если вы оставите открытие формы внутри транзакции, вы все равно получите проблему, хотя и в меньшем масштабе. Исключительная блокировка на сам документ (табличную часть документа) все равно будет удерживаться до закрытия формы. Поэтому смена режима блокировок — это хорошая мера для общей производительности системы, но она не отменяет необходимости исправления архитектурных ошибок в коде.

Итоги и рекомендации

Подводя итог нашему разбору, выделим основные правила работы с транзакциями и формами:

Соблюдение этих принципов позволит вам создавать стабильные и высокопроизводительные системы на базе 1С, в которых пользователи не будут мешать друг другу при выполнении повседневных операций.

← На главную