Ошибка с текстом «Конфликт блокировок при выполнении транзакции. Превышено максимальное время ожидания» является одной из самых распространенных проблем при параллельной работе пользователей. Она означает, что одна сессия попыталась прочитать или записать данные, которые уже удерживаются другой транзакцией, и не смогла дождаться освобождения ресурса в течение установленного таймаута (по умолчанию 20 секунд).
Разберем по шагам, как локализовать виновника конфликта (пользователя, документ и конкретную строку программного кода), а также выясним причины и способы предотвращения таких ситуаций.
Прежде чем приступать к поиску, проанализируем архитектуру используемых блокировок в вашей базе данных:
SERIALIZABLE или REPEATABLE READ на стороне MS SQL Server. В этом случае блокировки накладываются самим SQL-сервером (блокируются строки, страницы или таблицы целиком). При конфликте SQL Server переводит сессию в состояние ожидания.READ COMMITTED. Ошибка ожидания генерируется менеджером блокировок 1С.Если в базе используется автоматический режим блокировок, во время зависания сессий мы можем оперативно перехватить блокирующий и ожидающий SQL-запросы с помощью системных динамических представлений (DMV).
Выполним в SQL Server Management Studio (SSMS) следующий диагностический скрипт:
USE [ИмяВашейБазы];
SELECT
db.name AS DBName,
tl.resource_type,
CASE WHEN tl.resource_type = 'OBJECT' THEN
OBJECT_NAME(tl.resource_associated_entity_id, db.database_id)
ELSE
OBJECT_NAME(p.OBJECT_ID, db.database_id)
END AS BlockedObjectName,
tl.request_session_id AS Waiting_SPID,
wt.blocking_session_id AS Blocking_SPID,
h1.TEXT AS RequestingText,
h2.TEXT AS BlockingText,
tl.request_mode
FROM sys.dm_tran_locks AS tl
LEFT JOIN sys.databases db ON db.database_id = tl.resource_database_id
LEFT JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address
LEFT JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id
LEFT JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id
LEFT JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
WHERE wt.blocking_session_id IS NOT NULL;
Проанализируем результат выборки:
Обратите внимание: данный запрос возвращает данные только в момент, когда ожидание происходит прямо сейчас. Если таймаут уже истек и транзакция аварийно завершилась, таблица будет пустой.
Для гарантированного анализа постфактум настроим сбор событий Технологического журнала 1С. Это основной и самый надежный инструмент для поиска контекста ошибки в коде конфигурации.
Создадим или дополним конфигурационный файл logcfg.xml в каталоге настроек платформы (например, C:\Program Files\1cv8\conf\logcfg.xml):
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="C:\LOGS\1C_Locks" history="72">
<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>
Разберем ключевые свойства, которые будут зафиксированы в логах при возникновении конфликта:
WaitConnections — номер сеанса/соединения, удерживавшего нужные данные.WaitConnections предшествующее событие TLOCK, мы точно узнаем, кто именно держал ресурс и в какой процедуре конфигурации.Если в организации развернут инструмент 1С:ЦУП (входит в состав Корпоративного инструментального пакета), процесс расследования автоматизируется:
После выявления проблемного участка кода проанализируем типовые причины долгой блокировки регистров:
ЗафиксироватьТранзакцию().БлокировкаДанных в коде перед чтением/записью остатков исключает избыточные блокировки целых диапазонов таблиц на уровне СУБД.