Как устранить ошибку «Конфликт блокировок при выполнении транзакции» в 1С 8.3?

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

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

Разберем природу блокировок в 1С

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

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

Выясним причину конфликта с помощью технологического журнала

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

Рассмотрим пример настройки файла logcfg.xml для отлова конфликтов блокировок:


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

Проанализировав лог-файлы, мы сможем увидеть, какая именно транзакция удерживала ресурсы слишком долго и какой пользователь стал «жертвой» блокировки.

Реализуем управляемые блокировки в коде

Перейдем к практической части. Для того чтобы минимизировать вероятность конфликтов, мы должны использовать объект БлокировкаДанных. Его следует применять непосредственно перед началом выполнения запросов на чтение или запись данных в транзакции. Посмотрим на пример реализации блокировки остатков товаров при проведении документа:


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

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

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

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

В этом примере мы блокируем не весь регистр ТоварыНаСкладах, а только те комбинации Склад + Номенклатура, которые присутствуют в нашем документе. Это позволяет другим пользователям одновременно проводить документы по другим складам или товарам без каких-либо задержек.

Оптимизируем длительность транзакций

Важно помнить: чем дольше длится транзакция, тем выше риск конфликта. Рассмотрим основные правила оптимизации, которые помогут нам сократить время удержания блокировок:

  1. Выносите сложные расчеты за пределы транзакции. Все подготовительные действия, получение цен, остатков для визуализации и заполнение временных таблиц должны происходить до вызова метода Записать() или начала процедуры ОбработкаПроведения.
  2. Минимизируйте использование блокировок в циклах. Старайтесь блокировать все необходимые данные одним массивом перед циклом обработки.
  3. Проверьте индексы. Если запрос в транзакции выполняется медленно из-за отсутствия подходящего индекса в СУБД, блокировка будет удерживаться дольше положенного. Проверьте, что все измерения регистров, по которым идет отбор, индексированы.
  4. Порядок захвата ресурсов. Всегда блокируйте объекты в одном и том же порядке (например, сначала справочник Склады, затем регистр ТоварыНаСкладах). Это поможет избежать ситуации «Deadlock» (взаимная блокировка), когда два процесса ждут друг друга.

Разберем настройку SQL Server для работы с 1С

Для баз данных на MS SQL Server критически важным является включение режима Read Committed Snapshot Isolation (RCSI). Этот механизм позволяет 1С читать данные без установки блокировок на чтение, используя версии строк. Это радикально снижает количество конфликтов между отчетами и проведением документов.

Чтобы проверить и включить этот режим, используйте следующие SQL-команды (выполняются администратором БД):


-- Проверка текущего статуса
SELECT name, is_read_committed_snapshot_on FROM sys.databases WHERE name = 'ИмяВашейБазы';

-- Включение режима (требует отсутствия активных соединений)
ALTER DATABASE [ИмяВашейБазы] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [ИмяВашейБазы] SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE [ИмяВашейБазы] SET MULTI_USER;

Подведем итоги совместной работы

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

  1. Переведите конфигурацию и все ее объекты в режим Управляемых блокировок.
  2. Используйте БлокировкаДанных в коде для точечного захвата ресурсов.
  3. Сокращайте тело транзакции: делайте расчеты «до», а в транзакции выполняйте только запись.
  4. Настройте Read Committed Snapshot на стороне СУБД.
  5. Регулярно проводите аудит через Технологический журнал для выявления новых узких мест.

Соблюдение этих правил позволит вашей системе 1С работать быстро и стабильно даже при одновременной работе сотен пользователей.

← На главную