При работе с типовыми модулями интеграции «1С-Битрикс» и крупными конфигурациями, такими как УТ 11.4 или ERP, программисты часто сталкиваются с ошибкой Конфликт блокировок при выполнении транзакции. Ошибка сопровождается сообщением от SQL Server: Lock request time out period exceeded. Рассмотрим подробнее, почему возникает эта ситуация, проанализируем механизмы работы модуля обмена и разберем конкретные шаги по исправлению данной проблемы.
Проанализируем технологический стек. Ошибка чаще всего возникает в момент проведения документов, влияющих на остатки или цены (например, Приходный ордер на товары, Реализация товаров и услуг). Проблема заключается в том, что стандартный модуль Битрикса встраивается в обработчики событий ПередЗаписью или ПриЗаписи и вызывает метод ПланыОбмена.ЗарегистрироватьИзменения.
На уровне СУБД этот метод инициирует запись в таблицу изменений (обычно это таблица с окончанием _ChngR). Если в системе одновременно работают десятки пользователей или выполняются фоновые задания, несколько транзакций пытаются одновременно наложить исключительную блокировку (X-lock) на одни и те же ресурсы таблицы изменений. Ситуация усугубляется, если транзакция проведения документа длительная — пока 1С рассчитывает себестоимость или проверяет остатки, блокировка на узле обмена удерживается, заставляя другие сеансы ждать, пока не истечет время ожидания (timeout).
Это самый эффективный и быстрый способ «вылечить» блокировки без кардинальной переработки модуля. Как правило, модуль Битрикса регистрирует изменения «на каждый чих». Если объект уже зарегистрирован на узле, повторный вызов ЗарегистрироватьИзменения всё равно создает транзакционную нагрузку. Нам нужно добавить проверку: если объект уже ждет выгрузки, регистрировать его повторно не нужно.
Разберем, как это реализовать. Вместо прямого вызова типового кода регистрации, создадим свою функцию-обертку. Рассмотрим пример кода, который можно внедрить в общий модуль Б_ОбменССайтомСервер или использовать через расширение:
Функция НужноЛиРегистрироватьИзменение(Узел, Ссылка) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Истина КАК Зарегистрировано
|ИЗ
| ПланОбмена.Б_ОбменССайтом.Изменения КАК ТаблицаИзменений
|ГДЕ
| ТаблицаИзменений.Узел = &Узел
| И ТаблицаИзменений.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Узел", Узел);
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
Возврат НЕ Выборка.Следующий(); // Если записи нет, значит нужно регистрировать
КонецФункции
Теперь в местах вызова ПланыОбмена.ЗарегистрироватьИзменения(МассивУзловТовары, Запись.Номенклатура) мы добавляем условие:
Для Каждого Узел Из МассивУзловТовары Цикл
Если НужноЛиРегистрироватьИзменение(Узел, Запись.Номенклатура) Тогда
ПланыОбмена.ЗарегистрироватьИзменения(Узел, Запись.Номенклатура);
КонецЕсли;
КонецЦикла;
Этот подход позволяет избежать избыточных обращений к таблице изменений SQL Server, существенно снижая вероятность конфликтов блокировок.
Рассмотрим ситуацию, когда регистрация изменений всё равно мешает оперативной работе пользователей. В этом случае мы можем применить архитектурный паттерн «отложенной регистрации». Вместо того чтобы регистрировать данные в момент проведения документа, мы будем записывать информацию об изменениях во временный «буфер» — обычный регистр сведений.
Разберем этот алгоритм по шагам:
ОчередьРегистрацииБитрикс с единственным измерением Объект (тип ЛюбаяСсылка).ПланыОбмена.ЗарегистрироватьИзменения на простую запись в наш новый регистр. Запись в плоский регистр происходит значительно быстрее, чем работа с таблицей изменений плана обмена.ОчередьРегистрацииБитрикс, пачками регистрирует их на узлах плана обмена и очищает регистр.Важный момент: при таком подходе основная транзакция проведения документа (например, Приходного ордера) завершается мгновенно, не дожидаясь окончания блокировок в планах обмена.
Иногда корень проблемы кроется в настройках СУБД. Проанализируем параметры сервера. Для высоконагруженных баз 1С на MS SQL Server крайне рекомендуется включение режима RCSI (Read Committed Snapshot Isolation).
Этот режим позволяет операциям чтения не блокироваться операциями записи. Для этого выполним следующие SQL-команды (предварительно переведя базу в Single User mode):
ALTER DATABASE [ИмяВашейБазы] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [ИмяВашейБазы] SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE [ИмяВашейБазы] SET MULTI_USER;
Также проверим параметр MAXDOP (Maximum Degree of Parallelism). Для 1С рекомендуется устанавливать значение 1, чтобы предотвратить распараллеливание запросов, которое часто приводит к сложным взаимоблокировкам (Deadlocks) в таблицах изменений.
Посмотрим на логику самого модуля Битрикс. Часто он регистрирует номенклатуру даже тогда, когда в документе изменился реквизит, не имеющий отношения к сайту (например, Комментарий или Подразделение). Проанализируем код в общем модуле Б_ОбменССайтомСервер. Если мы видим, что регистрация происходит безусловно, стоит добавить проверку на «значимость» изменений. Для автоматизации этого процесса можно использовать готовую обработку для настройки гибкой регистрации изменений.
Например, в обработчике ПередЗаписью можно сравнить старые и новые значения ключевых полей (цена, остаток, наименование) с помощью ЭтотОбъект.Ссылка.Наименование и ЭтотОбъект.Наименование. Если ключевые поля не изменились, вызов регистрации можно пропустить.
Резюме: Чтобы навсегда избавиться от блокировок в связке 1С и Битрикс, необходимо комбинировать программные методы (проверка на дубли в плане обмена) и инфраструктурные настройки (RCSI на SQL Server). Это обеспечит стабильную работу системы даже при больших объемах номенклатуры и интенсивном документообороте.