Конфликт блокировок 1С: причины и как исправить

Дата: 18.09.2026 23:23:09
Блокировки
Транзакции
Управляемые блокировки
Проведение документов
Производительность
Комментарий:
0
Платформа:
8.3
Конфигурация:
Любая
Формы:
Любые

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

Что происходит, простыми словами

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

Проблема начинается, когда очередь не движется. У ожидания есть предел, по умолчанию 20 секунд. Если первая операция держит данные дольше, вторая получает ошибку. Данные при этом не портятся: 1С откатывает операцию целиком.

Что делать, если сотрудники видят эту ошибку

  • Разовая ошибка в час пик — повторите операцию через минуту, обычно она проходит.
  • Ошибка регулярно в одно и то же время — почти наверняка в это время работает тяжёлая операция: обмен с сайтом, загрузка заказов с маркетплейсов, закрытие месяца.
  • Ошибка у всех и постоянно — кто-то держит данные очень долго: зависший сеанс, массовая обработка или ошибка в доработке. Здесь нужен программист.

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

Как выглядит ошибка: варианты текста

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

Продолжение после «Конфликт блокировок при выполнении транзакции:»Где возникЧто значит
Превышено максимальное время ожидания предоставления блокировкиМенеджер управляемых блокировок 1СТранзакция ждала данные, занятые другим сеансом, дольше тайм-аута
Microsoft SQL Server …: Lock request time out period exceeded (native=1222)MS SQL, чаще в автоматическом режимеТо же ожидание, но на уровне СУБД
… was deadlocked on lock resources with another process and has been chosen as the deadlock victim (native=1205)MS SQLВзаимоблокировка на уровне СУБД
ERROR: deadlock detectedPostgreSQLВзаимоблокировка на стороне PostgreSQL

Взаимоблокировка на управляемых блокировках начинается с той же фразы, а отличить её надёжнее по технологическому журналу: там будет событие TDEADLOCK, а не TTIMEOUT. Если в тексте есть код ошибки СУБД, конфликт возник в самой СУБД. Сообщение о том, что объект заблокирован другим пользователем, — другая история: это объектная блокировка документа, открытого на редактирование.

Управляемые блокировки 1С и автоматический режим

Режим задаётся свойством конфигурации «Режим управления блокировкой данных».

АвтоматическийУправляемый
Кто блокируетСУБД по своим правиламПлатформа через менеджер блокировок; СУБД блокирует минимально
Чтение запросом в транзакцииБлокирует прочитанные данные до конца транзакцииНичего не блокирует без явной блокировки в коде
Что блокируетсяMS SQL — строки и диапазоны, при эскалации вся таблица; PostgreSQL и файловая база — таблицы целикомКонкретные значения полей, указанные в коде
Где встречаетсяСтарые и многие самописные конфигурацииСовременные типовые: БП 3.0, УТ 11, ERP и другие

Из-за табличных блокировок на PostgreSQL управляемый режим практически обязателен. Файловой базе при активной многопользовательской работе поможет только переход на клиент-серверный вариант.

Почему возникает конфликт

Ошибки блокировок 1С почти всегда сводятся к одному из сценариев ниже.

  • Долгие транзакции. Блокировки держатся до конца транзакции, и если в проведении идёт HTTP-запрос или тяжёлый запрос к базе, все, кому нужны те же остатки, ждут.
  • Массовое проведение. Перепроведение за месяц, групповая загрузка документов, обработка, которая оборачивает весь цикл в одну транзакцию.
  • Регламентные задания в рабочее время. Обмены, выгрузка на маркетплейсы, пересчёт итогов работают с теми же регистрами, что и пользователи.
  • Лишние блокировки. Регистр целиком вместо конкретного склада и товара, исключительный режим там, где хватило бы разделяемого.
  • Эскалация на СУБД. MS SQL при большом числе блокировок строк одной таблицы (порядка пяти тысяч в одном операторе) заменяет их блокировкой всей таблицы, и конфликтуют даже документы по разным товарам.
  • Взаимоблокировки. Транзакция А держит остаток товара X и ждёт товар Y, транзакция Б — наоборот. Лечится одинаковым порядком блокировок во всём коде.
  • Итоги регистров. Движения по ходовой позиции на одном складе пишутся в одну строку таблицы итогов, и при параллельном проведении она становится узким местом. Смягчает проблему свойство регистра «Разрешить разделение итогов».

Как найти виновника

Искать нужно не того, кто получил ошибку, а того, кто держал данные: пострадавший сеанс обычно ни в чём не виноват.

Журнал регистрации

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

Консоль кластера серверов

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

Технологический журнал

Самый точный инструмент, включается файлом logcfg.xml в каталоге conf платформы на сервере 1С. Для разбора блокировок нужны события TTIMEOUT (истекло ожидание управляемой блокировки), TDEADLOCK (взаимоблокировка) и TLOCK (установка управляемой блокировки).

В событиях TTIMEOUT и TLOCK есть свойство WaitConnections — номер соединения, которое держало данные. В TDEADLOCK участники взаимоблокировки перечислены в свойстве DeadlockConnectionIntersections: пары соединений и пространства блокировок, на которых они сцепились. По номеру соединения находите события TLOCK этого соединения, а в их контексте (Context) — строку кода, которая поставила блокировку.

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
	<log location="D:\techlog\locks" history="4">
		<event>
			<eq property="Name" value="TTIMEOUT"/>
			<eq property="p:processName" value="ИмяБазыВКластере"/>
		</event>
		<event>
			<eq property="Name" value="TDEADLOCK"/>
			<eq property="p:processName" value="ИмяБазыВКластере"/>
		</event>
		<event>
			<eq property="Name" value="TLOCK"/>
			<eq property="p:processName" value="ИмяБазыВКластере"/>
		</event>
		<property name="all"/>
	</log>
</config>

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

Со стороны СУБД

При ошибках с SQL-кодом смотрите блокировки в самой СУБД: в MS SQL — sys.dm_exec_requests (колонка blocking_session_id), в PostgreSQL — pg_locks и pg_stat_activity.

Конфликт блокировок в 1С 8.3: как исправить в коде

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

Контроль остатков при проведении

Типовой случай — документ списывает товар и проверяет остаток. В управляемом режиме запрос к остаткам ничего не блокирует: два документа одновременно прочитают «остаток 5», оба спишут по 5, и склад уйдёт в минус. Если же заблокировать весь регистр, документы будут проводиться строго по очереди. Правильно — заблокировать только нужные пары «склад + номенклатура».

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

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

	// Транзакцию на время проведения открывает платформа, своя не нужна.

	// 1. Одна строка на номенклатуру — без дублей.
	ТаблицаТоваров = Товары.Выгрузить(, "Номенклатура, Количество");
	ТаблицаТоваров.Свернуть("Номенклатура", "Количество");

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

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

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

	// 5. Нехватка — отказ. Блокировка снимется вместе с откатом транзакции.
	Пока Выборка.Следующий() Цикл
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = СтрШаблон("Не хватает ""%1"": требуется %2, на складе %3",
			Выборка.Номенклатура, Выборка.Нужно, Выборка.Есть);
		Сообщение.Сообщить();
		Отказ = Истина;
	КонецЦикла;

	Если Отказ Тогда
		Возврат;
	КонецЕсли;

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

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

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

  • Режим = РежимБлокировкиДанных.Исключительный — остатки будут меняться. С разделяемым режимом второй документ прочитал бы те же остатки, а при записи обе транзакции упёрлись бы друг в друга — классическая взаимоблокировка.
  • ИсточникДанных и ИспользоватьИзИсточникаДанных — значения номенклатуры берутся из свёрнутой таблицы, блокируется только то, что есть в документе.
  • Блокировка.Заблокировать() — блокировка ставится здесь и держится до конца транзакции проведения. Метода, который снял бы её раньше, нет.

Явная транзакция: прочитать и изменить

Если транзакцию открываете вы сами, например для выдачи номера из регистра-счётчика, блокировка ставится первым действием, а обработчик исключения обязательно отменяет транзакцию.

// Общий модуль (сервер). Регистр сведений «СчетчикиНомеров», непериодический:
// измерение Префикс (Строка), ресурс Значение (Число).

Функция СледующийНомер(Префикс) Экспорт

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

		МенеджерЗаписи = РегистрыСведений.СчетчикиНомеров.СоздатьМенеджерЗаписи();
		МенеджерЗаписи.Префикс = Префикс;
		МенеджерЗаписи.Прочитать();

		Номер = МенеджерЗаписи.Значение + 1;

		МенеджерЗаписи.Префикс = Префикс; // на случай, если записи ещё не было
		МенеджерЗаписи.Значение = Номер;
		МенеджерЗаписи.Записать();

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

	Возврат Номер;

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

Блокировка по префиксу не мешает сеансам с другими префиксами, а без неё два сеанса могут прочитать одно значение и выдать одинаковые номера.

Короткие транзакции вместо одной длинной

Частая причина массовых конфликтов — обработка, которая открывает транзакцию до цикла по сотням документов: блокировки копятся до последнего документа.

// Выполняется на сервере (общий модуль или модуль объекта обработки).

// Плохо: блокировки всех документов и их движений держатся до конца цикла.
Процедура ПерепровестиОднойТранзакцией(СписокДокументов)

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

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

// Лучше: каждый документ проводится в своей короткой транзакции.
Процедура ПерепровестиПоОдному(СписокДокументов)

	Для Каждого ДокументСсылка Из СписокДокументов Цикл
		ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
		Попытка
			ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
		Исключение
			ЗаписьЖурналаРегистрации("Перепроведение документов",
				УровеньЖурналаРегистрации.Ошибка, ДокументСсылка.Метаданные(), ДокументСсылка,
				ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
	КонецЦикла;

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

Если нужна атомарность («все документы или ни одного»), оставьте одну транзакцию, но уберите из неё всё лишнее и запускайте обработку вне рабочего времени. HTTP-запросы, работу с файлами и почтой из транзакции выносите всегда: до записи или в фоновое задание после неё.

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

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

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

Можно ли просто увеличить время ожидания блокировки?

Можно: параметр «Время ожидания блокировки данных» задаётся в конфигураторе в параметрах информационной базы. Но это лечит симптом: пользователи будут дольше ждать вместо быстрой ошибки. Годится как временная мера, пока ищете долгую транзакцию.

Теряются ли данные при конфликте блокировок?

Нет, транзакция отменяется целиком, документ достаточно провести повторно. Исключение — обработки из нескольких транзакций: часть изменений уже записана, результат стоит проверить.

Как узнать, какой режим блокировок в моей базе?

В конфигураторе откройте свойства корневого элемента конфигурации и найдите «Режим управления блокировкой данных». Если там «Автоматический и управляемый», режим задаётся у каждого документа и регистра свойством «Режим управления блокировкой». Явная транзакция НачатьТранзакцию() без параметра тогда будет автоматической; для управляемой укажите НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый).

Чем БлокировкаДанных отличается от метода Заблокировать() у объекта?

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

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

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

По теме

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

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

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

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


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