Кто держит блокировку в 1С и как это выяснить: от текста ошибки до запроса к СУБД

· 9 мин

Содержание

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

Частое заблуждение — считать, что это одна и та же проблема. Нет. В первом случае кто-то просто открыл документ на редактирование. Во втором две транзакции борются за одни и те же записи регистров, и решать это нужно совсем другими методами.

Какая блокировка мешает: объектная или транзакционная

В 1С 8.3 есть два разных механизма. От того, какой из них сработал, зависит весь дальнейший путь диагностики.

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

Транзакционные блокировки бывают управляемыми (их выдаёт менеджер блокировок 1С) и автоматическими (их ставит сама СУБД). Режим задан в свойствах корня конфигурации, свойство Режим управления блокировкой данных: Автоматический, Управляемый или Автоматический и управляемый. Типовые конфигурации на платформе 8.3 работают в управляемом режиме.

Типичные тексты, которые видит пользователь:

  • 🔒 Ошибка блокировки объекта. Объект уже заблокирован — объектная блокировка.
  • ⏳ Превышено максимальное время ожидания предоставления блокировки — управляемая транзакционная, таймаут около 20 секунд.
  • 🔁 Обнаружена взаимоблокировка (дедлок) — две транзакции ждут друг друга.
  • 🗄️ Lock request time out period exceeded или deadlocked on lock resources — сообщения SQL Server, признак автоматического режима или блокировки на уровне СУБД.
Диагностика: выберите симптом

Проверка блокировки объекта по сообщению и через «Активные пользователи»

Объектную блокировку платформа ставит, когда пользователь начинает менять документ или элемент справочника в форме. Снимается она при закрытии формы или при завершении сеанса.

Порядок проверки:

  1. Разверните текст ошибки целиком. В нём есть строки Компьютер, Пользователь, Сеанс, Начат и Приложение.
  2. Откройте список текущих сеансов: Все функции → Стандартные → Активные пользователи. Если пункта «Все функции» нет, включите его в параметрах программы (значок шестерёнки в шапке).
  3. Найдите сеанс с тем же номером. Совпадает время начала — это он.
  4. Свяжитесь с пользователем и попросите закрыть форму или записать изменения.
  5. Если пользователь ушёл, а сеанс висит — завершите сеанс (см. раздел про снятие блокировок).

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

Программная проверка: заблокирован ли объект

Иногда проверку нужно встроить в обработку: перед групповым изменением документов пропустить те, что сейчас кто-то редактирует. Для этого пробуют поставить блокировку и ловят исключение:

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

Метод Заблокирован() у объекта для этой задачи не подходит: он показывает, заблокировал ли объект текущий сеанс, а не чужой.

Консоль кластера и rac: кто держит блокировку на сервере

В клиент-серверном варианте главный инструмент — консоль администрирования серверов 1С. Консоль подключается к агенту сервера (порт 1540 по умолчанию).

Где смотреть:

  1. Откройте консоль, разверните кластер, затем Информационные базы → <ваша база>.
  2. Узел Блокировки показывает, какие сеансы держат блокировки и на каких объектах.
  3. Узел Сеансы показывает всех подключённых. Отсортируйте по колонке времени текущего вызова СУБД: сеанс, который минутами висит в вызове, — главный подозреваемый.
  4. Для подозрительного сеанса посмотрите пользователя, компьютер и приложение. Фоновое задание или COM-соединение часто держат блокировку дольше всех.

Без графической консоли то же делают через rac. Сервер администрирования ras должен быть запущен.

rac cluster list
rac infobase summary list --cluster=<uuid-кластера>
rac session list --cluster=<uuid-кластера> --infobase=<uuid-базы>
rac lock list --cluster=<uuid-кластера> --infobase=<uuid-базы>

Если какой-то параметр в вашей версии не принимается, сверьтесь со справкой rac help lock и rac help session.

Если кластер защищён администратором, добавьте к командам параметры с именем и паролем администратора кластера. Их список тоже есть в rac help.

Файловая база

В файловом варианте консоли нет. Блокировки там грубые, на уровне таблиц. Проверка сводится к «Активным пользователям»: кто в базе, что у него открыто, не запущена ли тяжёлая обработка. Если в файловой базе регулярно ловят ошибки блокировок при работе 5–10 человек, это повод переходить на клиент-серверный вариант.

Технологический журнал: TLOCK, TTIMEOUT и TDEADLOCK

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

Настройка — файл logcfg.xml в каталоге conf платформы, например C:\Program Files\1cv8\conf\logcfg.xml. Минимальный вариант для блокировок:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
  <log location="D:\techlog\locks" history="24">
    <event><eq property="name" value="TLOCK"/></event>
    <event><eq property="name" value="TTIMEOUT"/></event>
    <event><eq property="name" value="TDEADLOCK"/></event>
    <property name="all"/>
  </log>
</config>

Параметр history задаёт, сколько часов хранить файлы. Платформа перечитывает файл сама, перезапускать службу не нужно.

Событие TLOCK на нагруженной базе пишет гигабайты в час. Кладите журнал на диск со свободным местом и отключайте настройку сразу после сбора данных. Переполненный системный диск остановит сервер.

Что смотреть в событиях:

  • 🔍 TTIMEOUT — таймаут ожидания. Свойство WaitConnections содержит номер соединения, которое держало блокировку. Это и есть виновник.
  • 🔍 TDEADLOCK — взаимоблокировка. В свойстве DeadlockConnectionIntersections описано, кто кого ждал и на каком пространстве.
  • 🔍 TLOCK — каждая установка управляемой блокировки. Regions — какая таблица (например, AccumRg12345.DIMS), Locks — поля и значения, Context — строка кода.

Порядок разбора: находите TTIMEOUT, берёте номер из WaitConnections, затем ищете события TLOCK этого соединения незадолго до таймаута. Свойство Context укажет модуль и строку.

Проверка блокировок на уровне СУБД: SQL Server и PostgreSQL

В управляемом режиме основные блокировки живут в менеджере 1С, но запись данных всё равно блокирует строки в СУБД. В автоматическом режиме всё решает СУБД. Поэтому проверка на её стороне нужна, когда консоль 1С ничего подозрительного не показывает, а ожидание есть.

SQL Server

Кто кого блокирует прямо сейчас:

SELECT r.session_id,
       r.blocking_session_id,
       r.wait_type,
       r.wait_time / 1000 AS wait_sec,
       r.wait_resource,
       t.text AS sql_text
FROM sys.dm_exec_requests AS r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t
WHERE r.blocking_session_id <> 0;

Для быстрого взгляда подойдёт и EXEC sp_who2 — колонка BlkBy показывает номер блокирующего процесса. Детали по ресурсам даёт представление sys.dm_tran_locks.

PostgreSQL

Начиная с версии 9.6 есть функция pg_blocking_pids:

SELECT pid,
       pg_blocking_pids(pid) AS blocked_by,
       state,
       wait_event_type,
       now() - xact_start AS xact_age,
       left(query, 200) AS query
FROM pg_stat_activity
WHERE cardinality(pg_blocking_pids(pid)) > 0;

Отдельно ищите сеансы в состоянии idle in transaction с большим xact_age: транзакция открыта, но ничего не делает и держит блокировки.

Как связать таблицу СУБД с объектом 1С

В запросах вы увидите имена вида _AccumRg12345 или _Document678. Перевести их в имена метаданных помогает метод ПолучитьСтруктуруХраненияБазыДанных(). Выполните его во внешней обработке и найдите нужную таблицу в результате:

Структура = ПолучитьСтруктуруХраненияБазыДанных(, Истина);
Для Каждого Строка Из Структура Цикл
    Если СтрНайти(Строка.ИмяТаблицыХранения, "_AccumRg12345") > 0 Тогда
        Сообщить(Строка.Метаданные + " — " + Строка.ИмяТаблицы);
    КонецЕсли;
КонецЦикла;

Второй параметр Истина возвращает имена таблиц и полей СУБД, а не внутренние.

Поиск кода, который держит транзакцию слишком долго

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

  • 🐢 Тяжёлый запрос внутри транзакции. Например, при проведении считаются остатки по всем складам, а не по нужным.
  • 💬 Ожидание пользователя. Вопрос или диалог внутри открытой транзакции держит блокировку, пока человек думает.
  • 🔄 Повышение блокировки. Сначала данные читаются под разделяемой блокировкой, потом пишутся под исключительной. Две такие транзакции почти гарантированно дают взаимоблокировку.
  • 📦 Обработка всего массива одной транзакцией. Перепроведение месяца или загрузка тысяч документов в одной транзакции блокирует регистры для всех.
  • 🌐 Внешние вызовы. HTTP-запрос или обмен с другой базой внутри транзакции.
  • 🧩 Разный порядок захвата. Одна процедура блокирует сначала остатки, потом взаиморасчёты, другая — наоборот.

Правильный шаблон: заблокировать нужное пространство сразу в исключительном режиме и только потом читать.

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

Имя регистра здесь условное — подставьте свой. Чем уже область (не весь регистр, а конкретный склад), тем меньше конфликтов у других пользователей.

Журнал регистрации: разбор блокировок задним числом

Технологический журнал включают заранее. А если сбой был вчера и журнал не вёлся, остаётся журнал регистрации: Все функции → Стандартные → Журнал регистрации работает в любой конфигурации.

Как его использовать:

  1. Установите отбор по интервалу времени вокруг жалобы пользователя.
  2. В отборе укажите статус транзакции Отменена: откатанные транзакции часто и есть жертвы таймаутов.
  3. Посмотрите, кто в это время проводил документы пачкой, загружал данные или запускал регламентные операции.
  4. Сравните с расписанием регламентных и фоновых заданий. Закрытие месяца или обмен с сайтом в 11 утра — частый источник конфликтов.

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

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

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

СпособКогда применятьРиски
Попросить пользователя закрыть формуОбъектная блокировка, человек на местеНет
Дождаться окончания транзакцииИдёт плановое перепроведение или обменПользователи ждут
Завершить сеанс в «Активных пользователях» или консолиСеанс завис, пользователь недоступенНесохранённые данные теряются
Завершить процесс в СУБД (KILL, pg_terminate_backend)Только если сеанс 1С уже удалён, а процесс СУБД осталсяОткат транзакции, возможна долгая отмена

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

Завершать процесс напрямую в СУБД — крайняя мера. Сначала всегда удаляйте сеанс средствами 1С: платформа корректно освободит и свои управляемые блокировки.

Профилактика

Что сделать, чтобы блокировки не повторялись
Выполнено: 0 / 7

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

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

Почему блокировка висит, хотя пользователь закрыл 1С?
Клиент мог закрыться аварийно, а сеанс на сервере остался. Найдите его в консоли кластера и завершите вручную.
Можно ли увеличить время ожидания блокировки?
Да: в Конфигураторе Администрирование → Параметры информационной базы, поле времени ожидания блокировки данных (по умолчанию 20 секунд). Но увеличение лишь скрывает долгую транзакцию — лучше её найти и сократить.
Почему ошибка возникает только в момент закрытия месяца?
Закрытие месяца пишет большие объёмы в регистры и держит транзакции долго. Остальным в это время лучше не проводить документы в закрываемом периоде.
Блокирует ли отчёт данные?
Обычный отчёт читает данные без исключительных блокировок и в управляемом режиме другим не мешает. В автоматическом режиме чтение может ставить разделяемые блокировки СУБД.
Нужно ли перезагружать сервер 1С, чтобы снять блокировку?
Нет. Достаточно завершить конкретный сеанс. Перезапуск службы обрывает работу всех пользователей и оправдан только при сбое самого сервера.