Как устранить ошибку «Превышено максимальное время ожидания предоставления блокировки» в 1С?

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

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

Выясним причину возникновения блокировок

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

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

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

Разберем решение через оптимизацию запросов

Проанализируем пример кода, который часто становится причиной бед. Использование соединений с подзапросами в Запрос.Текст — это верный путь к эскалации блокировок. Рассмотрим, как переписать такой код. Вместо того чтобы заставлять SQL-сервер строить временные индексы на лету, мы подготовим данные заранее.

Посмотрим на пример неоптимального кода:


ВЫБРАТЬ
    Продажи.Номенклатура,
    Продажи.Количество
ИЗ
    РегистрНакопления.Продажи КАК Продажи
ГДЕ
    Продажи.Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ Справочник.Номенклатура ГДЕ ВидНоменклатуры = &Вид)

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


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

Запрос.УстановитьПараметр("Вид", НужныйВид);
Результат = Запрос.Выполнить();

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

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

Рассмотрим пошагово процесс установки блокировки для регистра накопления ОстаткиТоваров:

  1. Создаем объект ЭлементБлокировкиДанных.
  2. Указываем пространство блокировки (имя регистра).
  3. Устанавливаем режим (Исключительный или Разделяемый).
  4. Задаем источник данных (например, таблицу товаров из документа).

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


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

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

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

// Выполняем блокировку перед началом записи в транзакции
Блокировка.Заблокировать();

Этот метод гарантирует, что 1С:Предприятие заблокирует только те сочетания «Номенклатура-Склад», которые реально присутствуют в документе, не мешая другим пользователям работать с остальными позициями.

Проанализируем настройки СУБД и сервера приложений

Иногда программных методов недостаточно, и причину нужно искать в инфраструктуре. Выясним, какие параметры сервера могут влиять на время ожидания блокировок. В консоли кластера 1С существует параметр Время ожидания блокировки данных, который по умолчанию равен 20 секундам. Увеличивать его — плохая практика, так как это лишь накопит очередь сеансов. Вместо этого проанализируем настройки SQL-сервера. Для такой диагностики подойдёт обработка для анализа настроек, нагрузки и ожиданий на SQL-сервере.

Для MS SQL Server критически важно проверить следующие параметры:

Использование технологического журнала для поиска виновника

Если вы не можете определить, какой именно процесс вызывает блокировку, воспользуемся Технологическим журналом (ТЖ). Освоить этот мощный инструмент поможет статья про анализ технологического журнала. Нам необходимо настроить сбор событий TLOCK (блокировка в управляемом режиме) и TTIMEOUT (превышение времени ожидания).

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


<config xmlns="http://v8.1c.ru/7.4/config/logcfg">
  <log location="C:\Logs\Locks" history="24">
    <event>
      <eq property="Name" value="TLOCK"/>
    </event>
    <event>
      <eq property="Name" value="TTIMEOUT"/>
    </event>
    <property name="all"/>
  </log>
</config>

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

Подведем итоги и сформируем рекомендации

Для минимизации ошибок блокировок в вашей системе, придерживайтесь следующих правил. Во-первых, всегда старайтесь сокращать время транзакции: расчеты делайте до начала записи, а тяжелые операции (печать, рассылка) — после завершения транзакции. Во-вторых, активно внедряйте ВременныеТаблицы и Индексы в запросах к регистрам. В-третьих, убедитесь, что все ваши объекты переведены в режим управляемых блокировок и вы используете объект БлокировкаДанных перед проведением.

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

← На главную