При работе с высоконагруженными базами данных "1С:Предприятие 8.3", особенно в конфигурации "Бухгалтерия предприятия 3.0", разработчики часто сталкиваются с ошибками вида "Конфликт блокировок при выполнении транзакции: Не удалось заблокировать таблицу '_DOCUMENTJOURNALXXXXX'". Эта проблема особенно актуальна при выполнении внешних обработок по массовой загрузке или модификации данных. Проанализируем ситуацию, выясним, что скрывается за техническими именами таблиц, и разберем способы решения проблемы.
Рассмотрим внутреннее устройство хранения данных. Платформа 1С не создает в СУБД (MS SQL Server, PostgreSQL) таблицы с понятными нам именами вроде ЖурналДокументов.СчетаФактурыВыданные. Вместо этого используется система технических префиксов и числовых индексов. Префикс _DOCUMENTJOURNAL однозначно указывает на то, что данная таблица принадлежит объекту метаданных Журнал документов.
Числовой индекс (например, 20593) генерируется платформой в момент реструктуризации базы данных. Важно понимать, что в разных информационных базах даже с одинаковой конфигурацией эти индексы могут различаться. Структура такой таблицы обычно включает следующие поля:
_Document — ссылка на сам документ (составной тип данных)._Date_Time — дата и время документа, используемые для упорядочивания в журнале._Marked — булево значение, признак пометки на удаление._Posted — признак проведения документа._Number — номер документа для быстрого поиска и отображения._FldXXXX — дополнительные графы журнала, определенные в конфигураторе (например, "Контрагент", "Сумма").Проанализируем ситуацию: если база находится под замком (типовая конфигурация), мы не можем напрямую увидеть соответствие в конфигураторе. Для того чтобы понять, какой именно журнал блокируется, воспользуемся программным методом 1С ПолучитьСтруктуруХраненияБазыДанных(). Этот метод возвращает таблицу значений с полным описанием всех таблиц и полей в СУБД.
Разберем пример кода, который можно запустить во внешней обработке, чтобы найти имя объекта по имени таблицы:
ТаблицаСтруктуры = ПолучитьСтруктуруХраненияБазыДанных();
Для Каждого СтрокаСтруктуры Из ТаблицаСтруктуры Цикл
Если СтрокаСтруктуры.ИмяТаблицыХранения = "_DOCUMENTJOURNAL20593" Тогда
Сообщить("Это объект: " + СтрокаСтруктуры.ИмяТаблицы);
Прервать;
КонецЕсли;
КонецЦикла;
В типовой "Бухгалтерии предприятия 3.0" при записи документа СчетФактураВыданный чаще всего блокируются следующие журналы:
ЖурналДокументов.СчетаФактурыВыданные — специализированный журнал.ЖурналДокументов.ДокументыПокупателям — общий журнал для реализации и счетов-фактур.ЖурналДокументов.ЖурналОпераций — глобальный журнал, содержащий почти все документы системы.Почему возникает ошибка при записи документа? Проанализируем механизм работы платформы. Когда вы вызываете метод Записать(), 1С выполняет следующие действия в рамках одной транзакции:
_DocumentXXXX)._DOCUMENTJOURNALXXXX).Если в это же время другой пользователь или фоновое задание записывает другой документ, входящий в тот же самый журнал, возникает конкуренция. Платформа 1С в режиме управляемых блокировок пытается заблокировать только конкретные записи, но при определенных условиях (например, массовая вставка или обновление индексов) СУБД может принять решение о блокировке всей таблицы целиком (Lock Escalation).
Рассмотрим подробнее шаги, которые помогут устранить конфликт блокировок при работе внешней обработки.
1. Оптимизация транзакций во внешней обработке
Часто разработчики совершают ошибку, помещая весь цикл обработки документов в одну большую транзакцию. В этом случае блокировка на таблицу журнала будет удерживаться до самого завершения обработки. Разберем по шагам, как правильно организовать цикл:
// Неправильно: Начинать транзакцию до цикла
Для Каждого СтрокаДанных Из ДанныеДляЗагрузки Цикл
// Правильно: Ограничивать транзакцию одним документом или порцией
НачатьТранзакцию();
Попытка
ДокументОбъект = СоздатьДокумент(СтрокаДанных);
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписатьОшибкуВЛог(ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
2. Использование порционной фиксации
Если запись по одному документу слишком замедляет работу, можно использовать фиксацию порциями (например, по 50 документов). Это позволит "отпускать" блокировки таблицы _DOCUMENTJOURNAL для других пользователей, не давая транзакции разрастаться.
Счетчик = 0;
НачатьТранзакцию();
Для Каждого СтрокаДанных Из ДанныеДляЗагрузки Цикл
ДокументОбъект = СоздатьДокумент(СтрокаДанных);
ДокументОбъект.Записать();
Счетчик = Счетчик + 1;
Если Счетчик % 50 = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
3. Проверка режима управления блокировками
Проанализируем настройки конфигурации. В современных версиях БП 3.0 должен быть установлен режим Управляемый. Если в модуле менеджера или в коде обработки явно устанавливаются исключительные блокировки через объект БлокировкаДанных, убедитесь, что они охватывают минимально необходимый набор данных. Блокировать весь журнал _DOCUMENTJOURNAL без крайней необходимости нельзя.
4. Анализ через консоль кластера
Посмотрим на ситуацию глазами системного администратора. Если ошибка повторяется, откройте "Консоль администрирования кластера 1С". В разделе "Сеансы" можно увидеть, какой именно сеанс удерживает блокировку и какой объект (таблица) является причиной ожидания. Это поможет понять, не конфликтует ли ваша обработка, например, с регламентным заданием по обновлению полнотекстового поиска или закрытию месяца.
Знание того, что _DOCUMENTJOURNAL20593 — это конкретный журнал документов, позволяет нам сузить область поиска проблемы. Чаще всего решение кроется в сокращении времени жизни транзакции и отказе от монопольного захвата данных при массовой загрузке. Работайте с данными порционно, анализируйте структуру хранения через встроенные методы платформы, и конфликты блокировок перестанут быть препятствием для стабильной работы системы.