Блокировка данных 1С: управляемые блокировки с примерами

Дата: 09.10.2026 17:41:27
Блокировки
Управляемые блокировки
Транзакции
Проведение документов
Программирование 1С
Комментарий:
0
Платформа:
8.3
Конфигурация:
Любая
Формы:
Любые

Блокировка данных 1С нужна, когда код в одной транзакции читает данные, решает по ним и записывает результат: проверяет остаток и списывает товар, берёт последний номер и увеличивает счётчик, выбирает свободный заказ и помечает его взятым. Без блокировки между чтением и записью вклинивается другой сеанс: остаток уходит в минус, номер повторяется, заказ достаётся двоим. Ниже — устройство объекта БлокировкаДанных, выбор режима и шаблоны для проведения, обработки и счётчика.

Задача встречается в проведении с контролем остатков, обработках распределения, нумерации, очередях обмена с сайтом и маркетплейсами. Всё это — про управляемый режим: в свойствах корня конфигурации («Конфигурация» → «Открыть конфигурацию», правый щелчок по корню → «Свойства») «Режим управления блокировкой данных» равен «Управляемый», как в УТ 11.4 и КА 2.5; программно — Метаданные.РежимУправленияБлокировкойДанных. В автоматическом режиме целостность обеспечивает СУБД.

Не путайте понятия. Управляемая блокировка живёт внутри транзакции и защищает данные от других транзакций. Объектная (Заблокировать() у объекта, ЗаблокироватьДанныеДляРедактирования()) не даёт двоим редактировать один объект и транзакции не требует. Запрет входа на время обновления — это блокировка базы, а причины ожиданий и ошибок разобраны в статье о конфликте блокировок.

Как устроена блокировка данных 1С: объект БлокировкаДанных

Объект — коллекция элементов. Элемент создаёт метод Добавить("Пространство"), дальше задаётся, что блокировать:

  • Область — имя пространства, например "РегистрНакопления.ОстаткиТоваров";
  • Режим — РежимБлокировкиДанных.Исключительный (по умолчанию) или Разделяемый;
  • УстановитьЗначение(Поле, Значение) — условие на поле; вместо значения можно передать Новый Диапазон(Начало, Конец) с датами или числами, Неопределено открывает границу;
  • ИсточникДанных + ИспользоватьИзИсточникаДанных(ПолеПространства, ПолеИсточника) — значения из таблицы значений, табличной части или результата запроса, строка источника = комбинация. Одно поле нельзя задать и значением, и из источника.

Заблокировать() ставит все элементы, и держатся они до конца транзакции. Если область занята несовместимой чужой блокировкой, сеанс ждёт, а не дождавшись, получает «Конфликт блокировок при выполнении транзакции».

ПространствоПоля для условий
Справочник.Имя, Документ.Имя и другие ссылочные объектыСсылка; с 8.3.3 ещё реквизиты из свойства «Поля блокировки данных»
РегистрСведений.ИмяПериод (у периодического), измерения
РегистрСведений.Имя.НаборЗаписейРегистратор — только у подчинённого регистратору
РегистрНакопления.ИмяПериод, измерения
РегистрНакопления.Имя.НаборЗаписейРегистратор
РегистрБухгалтерии.ИмяПериод, Счет, Субконто1…, измерения
Константа.Имяполей нет

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

Блокировки конфликтуют, если их области пересекаются, а режимы несовместимы: «Склад = Основной» и «Номенклатура = Кабель» пересекаются на кабеле основного склада. Управляемые блокировки в 1С 8.3 ставятся на значения полей, а не на строки, поэтому заблокировать можно и комбинацию, которой в регистре ещё нет.

Два помощника для общего серверного модуля:

// Общий модуль БлокировкиДанныхСервер (флаг «Сервер»).

// Блокирует все комбинации значений из таблицы одним элементом.
// Параметры:
//   Пространство - Строка - например, "РегистрНакопления.ОстаткиТоваров".
//   Таблица - ТаблицаЗначений - только ключевые колонки, их имена совпадают
//             с полями пространства (измерения, Период, Ссылка).
//   Разделяемая - Булево - Истина, если данные только читаются.
// Пример: ЗаблокироватьПоТаблице("РегистрНакопления.ОстаткиТоваров",
//             Товары.Выгрузить(, "Склад, Номенклатура"));
Процедура ЗаблокироватьПоТаблице(Пространство, Таблица, Разделяемая = Ложь) Экспорт

	ПроверитьТранзакцию();
	Если Таблица.Количество() = 0 Тогда
		Возврат; // блокировать нечего
	КонецЕсли;

	Блокировка = Новый БлокировкаДанных;
	Элемент = Блокировка.Добавить(Пространство);
	Элемент.Режим = ?(Разделяемая, РежимБлокировкиДанных.Разделяемый,
		РежимБлокировкиДанных.Исключительный);
	Элемент.ИсточникДанных = Таблица;
	Для Каждого Колонка Из Таблица.Колонки Цикл
		Элемент.ИспользоватьИзИсточникаДанных(Колонка.Имя, Колонка.Имя);
	КонецЦикла;
	Блокировка.Заблокировать();

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

// Блокирует записи периодического регистра за интервал дат по одному
// значению измерения: например, курсы одной валюты за месяц перед перезаписью.
Процедура ЗаблокироватьЗаПериод(Пространство, Измерение, Значение, Начало, Конец) Экспорт

	ПроверитьТранзакцию();
	Блокировка = Новый БлокировкаДанных;
	Элемент = Блокировка.Добавить(Пространство); // режим по умолчанию - исключительный
	Элемент.УстановитьЗначение(Измерение, Значение);
	// Границы диапазона - Дата или Число; Неопределено - граница открыта.
	Элемент.УстановитьЗначение("Период", Новый Диапазон(Начало, Конец));
	Блокировка.Заблокировать();

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

// Без транзакции блокировка ничего не защищает - сообщаем об ошибке сразу.
Процедура ПроверитьТранзакцию()

	Если Не ТранзакцияАктивна() Тогда
		ВызватьИсключение НСтр("ru = 'Блокировку данных ставьте внутри транзакции'");
	КонецЕсли;

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

Исключительная и разделяемая блокировка: когда какая

У другого сеанса уже стоитПросим разделяемуюПросим исключительную
Разделяемаяставится сразуждём
Исключительнаяждёмждём

Исключительная блокировка 1С — для данных, которые вы меняете или по которым решаете, что записать: остатки, счётчики, очередь. Вторая транзакция с такой же блокировкой дождётся фиксации первой и прочитает уже новые значения.

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

Не повышайте режим внутри транзакции: прочитали под разделяемой и пишете те же данные (при записи платформа ставит исключительную). Если так сделают два сеанса сразу, каждый ждёт другого — взаимоблокировка. Собираетесь писать — сразу берите исключительную. Оба режима в одной блокировке:

// Модуль объекта документа «ОтгрузкаКлиенту» - вызывается из ОбработкаПроведения.
// Регистр сведений ЛимитыКлиентов: измерение Клиент, ресурс Лимит.
// Регистр накопления ДолгиКлиентов: измерение Клиент, ресурс Сумма.
// Лимит документ только читает, долг - проверяет и увеличивает.
Процедура ЗаблокироватьЛимитИДолг(Клиент)

	Блокировка = Новый БлокировкаДанных;

	// Разделяемая: читать лимит с такой же блокировкой могут и другие,
	// а изменить его никто не сможет, пока наша транзакция не закончится.
	ЭлементЛимит = Блокировка.Добавить("РегистрСведений.ЛимитыКлиентов");
	ЭлементЛимит.Режим = РежимБлокировкиДанных.Разделяемый;
	ЭлементЛимит.УстановитьЗначение("Клиент", Клиент);

	// Исключительная: долг клиента меняем, вторая отгрузка
	// тому же клиенту подождёт нашей фиксации.
	ЭлементДолг = Блокировка.Добавить("РегистрНакопления.ДолгиКлиентов");
	ЭлементДолг.Режим = РежимБлокировкиДанных.Исключительный;
	ЭлементДолг.УстановитьЗначение("Клиент", Клиент);

	Блокировка.Заблокировать(); // оба элемента - одним вызовом, до любого чтения

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

Шаблон 1. Контроль остатков при проведении

Расходный документ не должен увести остаток в минус, даже если десять человек проводят документы одновременно. Способов два: блокировка по измерениям до чтения остатков или запись с БлокироватьДляИзменения и проверка после записи. Как формируются движения документа и устроены остатки в запросе — в отдельных статьях.

Способ 1: блокировка по измерениям до чтения

Склад указан в строке табличной части, поэтому оба поля блокировки берутся из результата запроса.

// Модуль объекта документа «РасходнаяНакладная».
// Табличная часть Товары: Номенклатура, Склад, Количество (склад - в строке).
// Регистр накопления ОстаткиТоваров (остатки): измерения Склад и Номенклатура,
// ресурс Количество. Режим блокировок конфигурации - управляемый.

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

	// Транзакцию открыла платформа, документ в ней уже записан.
	Запрос = Новый Запрос;
	Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
	Запрос.УстановитьПараметр("Ссылка", Ссылка);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Т.Склад КАК Склад,
	|	Т.Номенклатура КАК Номенклатура,
	|	СУММА(Т.Количество) КАК Количество
	|ПОМЕСТИТЬ ВТ_Товары
	|ИЗ
	|	Документ.РасходнаяНакладная.Товары КАК Т
	|ГДЕ
	|	Т.Ссылка = &Ссылка
	|
	|СГРУППИРОВАТЬ ПО
	|	Т.Склад,
	|	Т.Номенклатура
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ВТ_Товары.Склад КАК Склад,
	|	ВТ_Товары.Номенклатура КАК Номенклатура
	|ИЗ
	|	ВТ_Товары КАК ВТ_Товары";
	Пакет = Запрос.ВыполнитьПакет();

	// 1. Блокировка - до чтения остатков и только на пары «склад + товар»
	//    из документа: каждая строка источника - одна комбинация.
	Блокировка = Новый БлокировкаДанных;
	Элемент = Блокировка.Добавить("РегистрНакопления.ОстаткиТоваров");
	Элемент.Режим = РежимБлокировкиДанных.Исключительный;
	Элемент.ИсточникДанных = Пакет[1];
	Элемент.ИспользоватьИзИсточникаДанных("Склад", "Склад");
	Элемент.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
	Блокировка.Заблокировать();

	// 2. Перепроведение: убираем старые движения, чтобы они не попали в остаток.
	Движения.ОстаткиТоваров.Записывать = Истина;
	Движения.ОстаткиТоваров.Записать();

	// 3. Остатки читаем уже под блокировкой.
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ВТ_Товары.Склад КАК Склад,
	|	ВТ_Товары.Номенклатура КАК Номенклатура,
	|	ВТ_Товары.Количество КАК Нужно,
	|	ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Есть
	|ИЗ
	|	ВТ_Товары КАК ВТ_Товары
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки(
	|				,
	|				(Склад, Номенклатура) В
	|					(ВЫБРАТЬ
	|						ВТ.Склад,
	|						ВТ.Номенклатура
	|					ИЗ
	|						ВТ_Товары КАК ВТ)) КАК Остатки
	|		ПО ВТ_Товары.Склад = Остатки.Склад
	|			И ВТ_Товары.Номенклатура = Остатки.Номенклатура
	|ГДЕ
	|	ВТ_Товары.Количество > ЕСТЬNULL(Остатки.КоличествоОстаток, 0)";
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = СтрШаблон("Склад %1, %2: нужно %3, в наличии %4",
			Выборка.Склад, Выборка.Номенклатура, Выборка.Нужно, Выборка.Есть);
		Сообщение.Сообщить();
		Отказ = Истина;
	КонецЦикла;

	Если Отказ Тогда
		Возврат; // транзакция откатится, блокировка снимется вместе с ней
	КонецЕсли;

	// 4. Движения. Набор с флагом Записывать платформа запишет после обработчика.
	Для Каждого СтрокаТовара Из Товары Цикл
		Движение = Движения.ОстаткиТоваров.ДобавитьРасход();
		Движение.Период = Дата;
		Движение.Склад = СтрокаТовара.Склад;
		Движение.Номенклатура = СтрокаТовара.Номенклатура;
		Движение.Количество = СтрокаТовара.Количество;
	КонецЦикла;

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

Разбор ключевых строк

  • Поля Склад и Номенклатура из источника — заблокированы только пары документа, проведение по другим товарам не ждёт.
  • ИсточникДанных = Пакет[1] — все комбинации одним элементом. Отдельный Заблокировать() на каждую строку медленнее и чаще ведёт к взаимоблокировкам.
  • Сначала Заблокировать(), потом запрос к остаткам: прочитанное до блокировки могло устареть, пока сеанс ждал.
  • Пустой набор, записанный до проверки, убирает старые движения при перепроведении.

Контролируется текущий остаток; для остатка на дату документа передайте в первый параметр Остатки() границу его момента. Запрос удобно отладить в бесплатной консоли запросов.

Способ 2: БлокироватьДляИзменения и проверка после записи

Свойство БлокироватьДляИзменения есть у наборов записей регистров накопления и бухгалтерии. Со значением Истина платформа при записи набора сама блокирует все комбинации измерений из его записей — остаётся записать движения и проверить, не стал ли остаток отрицательным. Так сделано в УТ 11.4: в модуле набора записей регистра ТоварыНаСкладах обработчик ПередЗаписью ставит БлокироватьДляИзменения = Истина.

// Тот же документ, второй способ: сначала записываем движения,
// потом проверяем, не ушёл ли остаток в минус.
Процедура ОбработкаПроведения(Отказ, РежимПроведения)

	Движения.ОстаткиТоваров.Записывать = Истина;
	Для Каждого СтрокаТовара Из Товары Цикл
		Движение = Движения.ОстаткиТоваров.ДобавитьРасход();
		Движение.Период = Дата;
		Движение.Склад = СтрокаТовара.Склад;
		Движение.Номенклатура = СтрокаТовара.Номенклатура;
		Движение.Количество = СтрокаТовара.Количество;
	КонецЦикла;

	// При записи платформа сама заблокирует все комбинации измерений
	// из набора - явная БлокировкаДанных не нужна.
	Движения.ОстаткиТоваров.БлокироватьДляИзменения = Истина;

	// Пишем все наборы сейчас. Флаг Записывать снимается,
	// повторной записи после обработчика не будет.
	Движения.Записать();

	// Остаток читаем после записи: в нём уже учтён этот документ,
	// а старые движения при перепроведении замещены новыми.
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Регистратор", Ссылка);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Остатки.Склад КАК Склад,
	|	Остатки.Номенклатура КАК Номенклатура,
	|	Остатки.КоличествоОстаток КАК Остаток
	|ИЗ
	|	РегистрНакопления.ОстаткиТоваров.Остатки(
	|			,
	|			(Склад, Номенклатура) В
	|				(ВЫБРАТЬ
	|					Д.Склад,
	|					Д.Номенклатура
	|				ИЗ
	|					РегистрНакопления.ОстаткиТоваров КАК Д
	|				ГДЕ
	|					Д.Регистратор = &Регистратор)) КАК Остатки
	|ГДЕ
	|	Остатки.КоличествоОстаток < 0";
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = СтрШаблон("Склад %1, %2: не хватает %3",
			Выборка.Склад, Выборка.Номенклатура, -Выборка.Остаток);
		Сообщение.Сообщить();
		Отказ = Истина; // откат вернёт и уже записанные движения
	КонецЦикла;

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

Плюсы: нет отдельного чтения перед записью и проблемы перепроведения — старые движения замещаются до проверки. Учтите: Движения.Записать() пишет все наборы с флагом Записывать, вызывайте его, когда сформированы все движения; в автоматическом режиме блокировок БлокироватьДляИзменения вызывает исключение.

Шаблон 2. Обработка «прочитать — изменить — записать»

Обработка-очередь: несколько сборщиков нажимают «Взять заказы», и каждый должен получить свои, без пересечений. Тот же приём подходит для фоновых заданий, которые параллельно разбирают общую очередь выгрузки. Код — в модуле формы: на клиенте только вызов и сообщение, работа с данными — в серверной функции без контекста.

// Модуль формы обработки «СборкаЗаказов».
// Регистр сведений ОчередьСборки (независимый, непериодический):
// измерение Заказ (ДокументСсылка.ЗаказКлиента),
// ресурсы ВРаботе (Булево) и Сборщик (Строка, 100).

&НаКлиенте
Процедура ВзятьЗаказы(Команда)

	Взятые = ВзятьСвободныеЗаказы();
	Если Взятые.Количество() = 0 Тогда
		ПоказатьПредупреждение(, "Свободных заказов нет, попробуйте через минуту.");
	Иначе
		ПоказатьОповещениеПользователя("Взято заказов: " + Взятые.Количество());
	КонецЕсли;

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

&НаСервереБезКонтекста
Функция ВзятьСвободныеЗаказы()

	Взятые = Новый Массив;

	// 1. Кандидаты - обычным запросом, без транзакции и без блокировки.
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ ПЕРВЫЕ 10
	|	Очередь.Заказ КАК Заказ
	|ИЗ
	|	РегистрСведений.ОчередьСборки КАК Очередь
	|ГДЕ
	|	НЕ Очередь.ВРаботе";
	Кандидаты = Запрос.Выполнить().Выгрузить();
	Если Кандидаты.Количество() = 0 Тогда
		Возврат Взятые;
	КонецЕсли;

	// Параметр важен только в режиме «Автоматический и управляемый».
	НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);
	Попытка
		// 2. Исключительная блокировка только на записи-кандидаты.
		Блокировка = Новый БлокировкаДанных;
		Элемент = Блокировка.Добавить("РегистрСведений.ОчередьСборки");
		Элемент.ИсточникДанных = Кандидаты;
		Элемент.ИспользоватьИзИсточникаДанных("Заказ", "Заказ");
		Блокировка.Заблокировать();

		// 3. Перечитываем под блокировкой: пока ждали, часть заказов
		//    могли забрать. Решаем только по свежим данным.
		Запрос.Текст =
		"ВЫБРАТЬ ПЕРВЫЕ 5
		|	Очередь.Заказ КАК Заказ
		|ИЗ
		|	РегистрСведений.ОчередьСборки КАК Очередь
		|ГДЕ
		|	Очередь.Заказ В (&Кандидаты)
		|	И НЕ Очередь.ВРаботе";
		Запрос.УстановитьПараметр("Кандидаты", Кандидаты.ВыгрузитьКолонку("Заказ"));
		Выборка = Запрос.Выполнить().Выбрать();

		// 4. Изменяем и записываем.
		Пока Выборка.Следующий() Цикл
			Запись = РегистрыСведений.ОчередьСборки.СоздатьМенеджерЗаписи();
			Запись.Заказ = Выборка.Заказ;
			Запись.ВРаботе = Истина;
			Запись.Сборщик = ИмяПользователя();
			Запись.Записать(); // замещает запись с тем же заказом
			Взятые.Добавить(Выборка.Заказ);
		КонецЦикла;

		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;

	Возврат Взятые;

КонецФункции

Ключевой шаг — третий. Кандидатов выбрали без блокировки, и пока сеанс ждал Заблокировать(), сосед мог забрать часть заказов. Решение принимается только по данным, прочитанным после блокировки, иначе второй сборщик перепишет чужой заказ на себя. Транзакция короткая: сама сборка, печать и любые долгие действия идут после фиксации.

Шаблон 3. Счётчик номеров в регистре сведений

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

// Общий модуль (флаг «Сервер»). Регистр сведений Нумераторы, непериодический:
// измерения ВидНумерации (Строка, 50) и Год (Число, 4), ресурс Последний (Число, 10).
// Возвращает первый и последний номер выделенной пачки.
Функция ВыделитьНомера(ВидНумерации, Год, Количество = 1) Экспорт

	// Внутри чужой транзакции блокировка счётчика продержится до её конца.
	// Если пропуски номеров допустимы, вызывайте до начала основной транзакции.
	НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);
	Попытка
		// Блокируем ключ счётчика. Записи может ещё не быть - не важно:
		// управляемая блокировка ставится на значения полей, а не на строки.
		Блокировка = Новый БлокировкаДанных;
		Элемент = Блокировка.Добавить("РегистрСведений.Нумераторы");
		Элемент.УстановитьЗначение("ВидНумерации", ВидНумерации);
		Элемент.УстановитьЗначение("Год", Год);
		Блокировка.Заблокировать();

		Набор = РегистрыСведений.Нумераторы.СоздатьНаборЗаписей();
		Набор.Отбор.ВидНумерации.Установить(ВидНумерации);
		Набор.Отбор.Год.Установить(Год);
		Набор.Прочитать();

		Если Набор.Количество() = 0 Тогда
			Запись = Набор.Добавить();
			Запись.ВидНумерации = ВидНумерации;
			Запись.Год = Год;
		Иначе
			Запись = Набор[0];
		КонецЕсли;

		Первый = Запись.Последний + 1;
		Запись.Последний = Запись.Последний + Количество;
		Набор.Записать();

		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;

	Возврат Новый Структура("Первый, Последний", Первый, Первый + Количество - 1);

КонецФункции

Вызов ВыделитьНомера("ЗаявкаССайта", 2026, 50) выдаёт 50 номеров за одно обращение к счётчику. Блокировка стоит на ключе «вид нумерации + год», разные счётчики друг другу не мешают, а пока записи нет, два сеанса всё равно не создадут две «первые». Выбор за вами: внутри транзакции записи документа номер при откате вернётся (нумерация без пропусков), но остальные будут ждать конца проведения. Если пропуски допустимы, вызывайте функцию до основной транзакции.

Как избежать лишних блокировок и ожиданий

  • Узкая область. Все ключевые измерения, значения — из документа через источник данных. Блокировка целого склада останавливает проведение всех документов по нему.
  • Один вызов в начале. Все элементы — в одну БлокировкаДанных, Заблокировать() — до первого чтения и сразу в нужном режиме.
  • Короткие транзакции. HTTP-запросы, файлы, долгие расчёты — до НачатьТранзакцию() или после фиксации; подробнее — в статье о транзакциях.
  • Горячие записи. Номера выдавайте заранее или пачкой, общие настройки читайте под разделяемой блокировкой.
  • Период — тоже поле. Блокировка Период через Диапазон пересекается со всеми блокировками регистра без условия на период: их область покрывает все даты.
  • Режим «Автоматический и управляемый». Явную транзакцию открывайте с параметром РежимУправленияБлокировкойДанных.Управляемый, как в шаблонах выше: без него она будет автоматической.

Типичные ошибки

  • Блокировка после чтения. Сначала запрос к остаткам, потом Заблокировать() — проверка идёт по устаревшим данным.
  • «ДЛЯ ИЗМЕНЕНИЯ» вместо блокировки. В управляемом режиме платформа это предложение запроса игнорирует; код из автоматического режима переписывайте на БлокировкаДанных.
  • Весь регистр вместо пар измерений. Пользователи ждут друг друга и получают «Конфликт блокировок при выполнении транзакции» на документах без общих товаров.
  • Разделяемая, а потом запись тех же данных. Два таких сеанса — взаимоблокировка.
  • Защищён один документ из трёх. Управляемая блокировка останавливает только тех, кто блокирует те же данные: если товар списывают три документа, а блокирует один, два других уведут остаток в минус.
  • Код на клиенте. БлокировкаДанных доступна на сервере, в толстом клиенте и внешнем соединении; в процедуре &НаКлиенте управляемой формы — ошибка «Тип не определен (БлокировкаДанных)». О контекстах — в статье про директивы компиляции.
  • Нет транзакции. Блокировка живёт только внутри транзакции: забыли НачатьТранзакцию() — данные не защищены. В помощнике выше это ловит ТранзакцияАктивна().

Частые вопросы

Как снять управляемую блокировку раньше конца транзакции?

Никак: метода «Разблокировать» нет. Блокировки снимаются при фиксации или отмене самой внешней транзакции, вложенная пара НачатьТранзакцию()/ЗафиксироватьТранзакцию() их не снимает. Всё, что можно сделать вне транзакции, делайте вне её.

Мешает ли исключительная блокировка отчётам и обычным запросам?

Менеджер управляемых блокировок проверяет только тех, кто сам блокирует те же данные, поэтому обычный запрос отчёта из-за неё в очередь не встаёт. Зато он может прочитать данные, которые через секунду изменятся: для отчёта это нормально, для решения «можно ли списать» — нет.

Нужна ли БлокировкаДанных, если я просто записываю объект или набор записей?

Нет, записываемые данные платформа блокирует сама. Явная блокировка нужна, когда записываемое зависит от прочитанного: остатков, счётчика, статуса в очереди.

Как заблокировать документ или элемент справочника?

Пространство — полное имя объекта, поле — Ссылка: Блокировка.Добавить("Документ.РасходнаяНакладная").УстановитьЗначение("Ссылка", ДокументСсылка), затем Блокировка.Заблокировать(). Для списка ссылок — источник данных с колонкой Ссылка. С 8.3.3 полями блокировки могут быть и реквизиты из свойства «Поля блокировки данных».

Когда проще заказать

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

По теме

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.


1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.