Кто держит блокировку в 1С и как это выяснить: от текста ошибки до запроса к СУБД
Содержание
Проверить блокировку объекта в 1С проще всего по тексту самой ошибки: сообщение Ошибка блокировки объекта. Объект уже заблокирован сразу называет компьютер, пользователя и номер сеанса, который держит документ. Если же пользователь видит Конфликт блокировок при выполнении транзакции: Превышено максимальное время ожидания предоставления блокировки, виновника ищут через консоль кластера и технологический журнал.
Частое заблуждение — считать, что это одна и та же проблема. Нет. В первом случае кто-то просто открыл документ на редактирование. Во втором две транзакции борются за одни и те же записи регистров, и решать это нужно совсем другими методами.
Какая блокировка мешает: объектная или транзакционная
В 1С 8.3 есть два разных механизма. От того, какой из них сработал, зависит весь дальнейший путь диагностики.
| Признак | Объектная (пессимистическая) блокировка | Транзакционная блокировка |
|---|---|---|
| Когда возникает | Второй пользователь пытается изменить объект, открытый на редактирование | Две транзакции пишут или читают одни данные |
| Текст ошибки | Ошибка блокировки объекта. Объект уже заблокирован | Конфликт блокировок при выполнении транзакции |
| Сколько живёт | Пока открыта форма или жив сеанс | Пока не закончится транзакция |
| Кто виноват | Пользователь с открытой формой | Код проведения, обработка, регламентное задание |
| Где искать | Текст ошибки, «Активные пользователи», консоль | Консоль, техжурнал, СУБД |
Транзакционные блокировки бывают управляемыми (их выдаёт менеджер блокировок 1С) и автоматическими (их ставит сама СУБД). Режим задан в свойствах корня конфигурации, свойство Режим управления блокировкой данных: Автоматический, Управляемый или Автоматический и управляемый. Типовые конфигурации на платформе 8.3 работают в управляемом режиме.
Типичные тексты, которые видит пользователь:
- 🔒
Ошибка блокировки объекта. Объект уже заблокирован— объектная блокировка. - ⏳
Превышено максимальное время ожидания предоставления блокировки— управляемая транзакционная, таймаут около 20 секунд. - 🔁
Обнаружена взаимоблокировка(дедлок) — две транзакции ждут друг друга. - 🗄️
Lock request time out period exceededилиdeadlocked on lock resources— сообщения SQL Server, признак автоматического режима или блокировки на уровне СУБД.
Проверка блокировки объекта по сообщению и через «Активные пользователи»
Объектную блокировку платформа ставит, когда пользователь начинает менять документ или элемент справочника в форме. Снимается она при закрытии формы или при завершении сеанса.
Порядок проверки:
- Разверните текст ошибки целиком. В нём есть строки
Компьютер,Пользователь,Сеанс,НачатиПриложение. - Откройте список текущих сеансов:
Все функции → Стандартные → Активные пользователи. Если пункта «Все функции» нет, включите его в параметрах программы (значок шестерёнки в шапке). - Найдите сеанс с тем же номером. Совпадает время начала — это он.
- Свяжитесь с пользователем и попросите закрыть форму или записать изменения.
- Если пользователь ушёл, а сеанс висит — завершите сеанс (см. раздел про снятие блокировок).
Номер сеанса надёжнее имени пользователя. Под одной учётной записью могут сидеть два человека с разных компьютеров, а номер сеанса уникален.
Программная проверка: заблокирован ли объект
Иногда проверку нужно встроить в обработку: перед групповым изменением документов пропустить те, что сейчас кто-то редактирует. Для этого пробуют поставить блокировку и ловят исключение:
Функция ОбъектЗанятДругим(Ссылка, ИдентификаторФормы)
Попытка
ЗаблокироватьДанныеДляРедактирования(Ссылка, , ИдентификаторФормы);
Исключение
// Объект уже заблокирован другим сеансом
Возврат Истина;
КонецПопытки;
РазблокироватьДанныеДляРедактирования(Ссылка, ИдентификаторФормы);
Возврат Ложь;
КонецФункции
Метод Заблокирован() у объекта для этой задачи не подходит: он показывает, заблокировал ли объект текущий сеанс, а не чужой.
Консоль кластера и rac: кто держит блокировку на сервере
В клиент-серверном варианте главный инструмент — консоль администрирования серверов 1С. Консоль подключается к агенту сервера (порт 1540 по умолчанию).
Где смотреть:
- Откройте консоль, разверните кластер, затем
Информационные базы → <ваша база>. - Узел
Блокировкипоказывает, какие сеансы держат блокировки и на каких объектах. - Узел
Сеансыпоказывает всех подключённых. Отсортируйте по колонке времени текущего вызова СУБД: сеанс, который минутами висит в вызове, — главный подозреваемый. - Для подозрительного сеанса посмотрите пользователя, компьютер и приложение. Фоновое задание или 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-запрос или обмен с другой базой внутри транзакции.
- 🧩 Разный порядок захвата. Одна процедура блокирует сначала остатки, потом взаиморасчёты, другая — наоборот.
Правильный шаблон: заблокировать нужное пространство сразу в исключительном режиме и только потом читать.
НачатьТранзакцию();
Попытка
Блокировка = Новый БлокировкаДанных;
Элемент = Блокировка.Добавить("РегистрНакопления.ОстаткиТоваров");
Элемент.Режим = РежимБлокировкиДанных.Исключительный;
Элемент.УстановитьЗначение("Склад", Склад);
Блокировка.Заблокировать();
// чтение остатков и запись движений
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
Имя регистра здесь условное — подставьте свой. Чем уже область (не весь регистр, а конкретный склад), тем меньше конфликтов у других пользователей.
Журнал регистрации: разбор блокировок задним числом
Технологический журнал включают заранее. А если сбой был вчера и журнал не вёлся, остаётся журнал регистрации: Все функции → Стандартные → Журнал регистрации работает в любой конфигурации.
Как его использовать:
- Установите отбор по интервалу времени вокруг жалобы пользователя.
- В отборе укажите статус транзакции
Отменена: откатанные транзакции часто и есть жертвы таймаутов. - Посмотрите, кто в это время проводил документы пачкой, загружал данные или запускал регламентные операции.
- Сравните с расписанием регламентных и фоновых заданий. Закрытие месяца или обмен с сайтом в 11 утра — частый источник конфликтов.
Журнал регистрации не покажет саму блокировку. Зато он даёт картину: что делалось в базе в момент сбоя и чьи транзакции откатились. Если ошибки повторяются, по этой картине выбирают время для включения техжурнала.
Как снять блокировку и не допустить повторения
Снять блокировку можно только одним способом — завершить транзакцию или сеанс, который её держит.
| Способ | Когда применять | Риски |
|---|---|---|
| Попросить пользователя закрыть форму | Объектная блокировка, человек на месте | Нет |
| Дождаться окончания транзакции | Идёт плановое перепроведение или обмен | Пользователи ждут |
| Завершить сеанс в «Активных пользователях» или консоли | Сеанс завис, пользователь недоступен | Несохранённые данные теряются |
Завершить процесс в СУБД (KILL, pg_terminate_backend) | Только если сеанс 1С уже удалён, а процесс СУБД остался | Откат транзакции, возможна долгая отмена |
Завершение сеанса прерывает работу пользователя без сохранения, а незаконченная транзакция откатывается целиком. Предупредите человека и не завершайте сеансы фоновых заданий закрытия месяца или обмена посреди работы — их придётся запускать заново.
Завершать процесс напрямую в СУБД — крайняя мера. Сначала всегда удаляйте сеанс средствами 1С: платформа корректно освободит и свои управляемые блокировки.
Профилактика
Для доработанных конфигураций полезно включить разделение итогов у регистров накопления (флажок «Разрешить разделение итогов» в свойствах регистра). Тогда параллельная запись движений по одним измерениям меньше конфликтует.
Частые вопросы
Почему блокировка висит, хотя пользователь закрыл 1С?
Можно ли увеличить время ожидания блокировки?
Администрирование → Параметры информационной базы, поле времени ожидания блокировки данных (по умолчанию 20 секунд). Но увеличение лишь скрывает долгую транзакцию — лучше её найти и сократить.