Почему управляемая блокировка в 1С не запрещает чтение данных из другого сеанса?

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

При работе с механизмом управляемых блокировок в 1С начинающие (и даже опытные) разработчики часто сталкиваются с ситуацией, которая кажется нелогичной с точки зрения классических СУБД. Вы устанавливаете Исключительный режим блокировки на регистр, останавливаете выполнение кода точкой останова, открываете другое окно программы, выполняете запрос к этому же регистру — и данные успешно считываются. Возникает закономерный вопрос: почему блокировка «не работает»? В этой статье мы подробно проанализируем внутреннее устройство управляемых блокировок, выясним причины такого поведения и разберем правильные методы обеспечения целостности данных.

Различие между блокировками СУБД и управляемыми блокировками

Для начала разберем ключевое отличие, которое часто сбивает с толку. В автоматическом режиме блокировок платформа 1С полностью полагалась на механизмы СУБД (MS SQL Server, PostgreSQL и др.). Когда вы блокировали таблицу, СУБД физически запрещала доступ к страницам данных или строкам для других транзакций. Это обеспечивало жесткую изоляцию, но приводило к серьезным проблемам с производительностью и параллельностью работы пользователей.

В режиме управляемых блокировок ситуация кардинально меняется. Рассмотрим основные тезисы:

  1. Место хранения: Управляемые блокировки существуют только в памяти сервера приложений 1С (в специальном менеджере блокировок). СУБД о них «ничего не знает».
  2. Уровень изоляции СУБД: При использовании управляемого режима 1С переводит транзакции СУБД на минимально необходимый уровень (обычно Read Committed). Это позволяет СУБД разрешать чтение данных, даже если в другой транзакции эти данные сейчас изменяются.
  3. Принцип «взаимного согласия»: Управляемая блокировка работает только в том случае, если оба процесса (и тот, кто блокирует, и тот, кто пытается прочитать/записать) явно обращаются к менеджеру блокировок 1С.

Проанализируем ситуацию на примере кода

Посмотрим на код, который часто используют разработчики в модулях проведения документов (процедура ОбработкаПроведения):


Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить();
ЭлементБлокировки.Область = "РегистрНакопления.ТоварыНаСкладах";
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();

Когда этот код выполняется, сервер приложений помечает в своей памяти: «Регистр ТоварыНаСкладах заблокирован транзакцией №123 исключительно». Если в этот момент вы откроете консоль запросов и просто выполните ВЫБРАТЬ * ИЗ РегистрНакопления.ТоварыНаСкладах, платформа 1С отправит обычный SQL-запрос к базе данных. База данных, работая в режиме Read Committed, увидит, что данные доступны для чтения, и вернет их. Она не знает, что в памяти сервера приложений висит какая-то «управляемая блокировка».

Как заставить блокировку работать?

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

Сценарий 1: Конкурентное изменение данных

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

Сценарий 2: Чтение данных с контролем остатков

Самая частая ошибка — чтение данных запросом без предварительной установки блокировки. Чтобы чтение гарантированно дождалось окончания записи в другом сеансе, мы должны написать следующий код перед выполнением запроса:


// Создание объекта блокировка
Блокировка = Новый БлокировкаДанных;

// Добавление элемента блокировки
Элемент = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");

// Установка режима блокировки
// Используем Исключительный, если планируем изменять, 
// или Разделяемый, если только читаем для контроля
Элемент.Режим = РежимБлокировкиДанных.Исключительный;

// Установка конкретных полей (гранулярность)
// Важно блокировать не весь регистр, а только нужные измерения
Элемент.УстановитьЗначение("Склад", СкладСсылка);

// Блокировка данных
Блокировка.Заблокировать();

// Только ПОСЛЕ этого выполняем запрос
Запрос = Новый Запрос("ВЫБРАТЬ ... ИЗ РегистрНакопления.ТоварыНаСкладах ГДЕ Склад = &Склад");
// ... выполнение запроса

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

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

Одним из главных преимуществ управляемого режима является возможность блокировать данные очень узко. Разберем пример, где мы блокируем не весь регистр, а только конкретный список номенклатуры на конкретном складе. Это позволяет другим пользователям одновременно проводить документы по другим складам или товарам, не мешая друг другу.


Блокировка = Новый БлокировкаДанных;
Элемент = Блокировка.Добавить("РегистрНакопления.ОстаткиНоменклатуры");
Элемент.Режим = РежимБлокировкиДанных.Исключительный;

// Блокируем конкретный склад
Элемент.УстановитьЗначение("Склад", ВыбранныйСклад);

// Блокируем список номенклатуры из табличной части документа
Элемент.ИсточникДанных = СписокТоваров; 
Элемент.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");

Блокировка.Заблокировать();

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

Почему 1С выбрала такой путь?

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

Выводы и рекомендации

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

  1. Всегда работайте в транзакции. Управляемая блокировка за пределами транзакции бесполезна.
  2. Соблюдайте симметрию. Если вы хотите, чтобы чтение ждало окончания записи, вы обязаны поставить управляемую блокировку и при записи, и при чтении.
  3. Уточняйте пространство блокировок. Никогда не блокируйте весь регистр без необходимости. Используйте УстановитьЗначение для измерений (Склад, Организация, Номенклатура).
  4. Не путайте уровни. Помните, что данные в SQL-консоли или в динамическом списке могут быть видны даже при наличии активной блокировки в коде проведения. Это нормальное поведение системы, направленное на повышение параллельности.

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

← На главную