Как заблокировать конкретный объект в 1С и обеспечить целостность данных в транзакции

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

1. Гарантия атомарности: транзакции в 1С

Для обеспечения принципа «все или ничего» используются транзакции СУБД. Все изменения, выполняемые между вызовами НачатьТранзакцию() и ЗафиксироватьТранзакцию(), либо успешно сохраняются в базе данных целиком, либо полностью отменяются при вызове ОтменитьТранзакцию().

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

2. Пессимистическая блокировка через метод Заблокировать()

Вызов метода Заблокировать() у конкретного объекта (например, СправочникОбъект или ДокументОбъект) накладывает пессимистическую (сеансовую) блокировку. Разберем особенности её работы:

  1. Она работает в памяти менеджера блокировок платформы и защищает объект от редактирования другими пользователями через формы интерактивного ввода.
  2. Она не привязана строго к транзакции СУБД и может использоваться вне контекста транзакции.
  3. Основная цель — предотвратить ошибку «Версия объекта была изменена или удалена» при попытке пользователя записать форму, которую одновременно правит кто-то другой.

3. Управляемая транзакционная блокировка: объект БлокировкаДанных

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

Посмотрим на пример кода, который блокирует конкретную ссылку справочника:


Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Полуфабрикаты");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНаПолуфабрикат);
Блокировка.Заблокировать();

Рассмотрим ключевые моменты работы с БлокировкаДанных:

  1. Режим управления блокировками: Конфигурация или конкретный объект метаданных должны находиться в режиме Управляемый. Если объект находится в автоматическом режиме, явный вызов метода Заблокировать() вызовет ошибку, если при старте транзакции не был явно передан режим РежимУправленияБлокировкойДанных.Управляемый.
  2. Атомарность блокировки: В один объект БлокировкаДанных можно добавить несколько элементов для разных таблиц и заблокировать их за один вызов метода Заблокировать().
  3. Предотвращение взаимных блокировок (Deadlocks): Если вы блокируете массив объектов, их обязательно нужно предварительно отсортировать (например, по ссылке или ее уникальному идентификатору). Это гарантирует, что все параллельные сеансы будут накладывать блокировки строго в одинаковом порядке.

4. Правильный шаблон обработки транзакции и блокировок

Рассмотрим готовый пример корректного выполнения манипуляций с данными в единой транзакции с установкой управляемой блокировки:


НачатьТранзакцию();
Попытка
    // 1. Создаем и настраиваем управляемую блокировку
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("Справочник.Полуфабрикаты");
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНаОбъект);
    
    // 2. Устанавливаем блокировку до чтения и изменения данных
    Блокировка.Заблокировать();
    
    // 3. Выполняем действия с объектом
    Объект = СсылкаНаОбъект.ПолучитьОбъект();
    Если Объект <> Неопределено Тогда
        // Выполняем необходимые изменения
        Объект.Записать();
    КонецЕсли;
    
    // 4. Фиксируем транзакцию
    ЗафиксироватьТранзакцию();
Исключение
    // 5. В случае ошибки отменяем транзакцию и пробрасываем ошибку дальше
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;

Выясним причину особенностей работы в файловом режиме: в файловой базе платформа использует логический менеджер управляемых блокировок для защиты записей, однако на уровне файла базы данных блокируется вся таблица целиком. При переходе на клиент-серверный вариант (например, MS SQL или PostgreSQL) управляемые блокировки обеспечивают высокую параллельность работы, блокируя только нужные строки на время транзакции.

← На главную