Каждое закрытие месяца для бухгалтеров и ИТ-специалистов крупных производственных предприятий превращается в настоящее испытание. Запуск ключевого документа «Расчет себестоимости выпуска» (РСВ) в конфигурации «1С:Управление производственным предприятием» (УПП) нередко полностью парализует работу всей системы. Пользователи начинают массово жаловаться на невозможность провести даже самые простые, казалось бы, никак не связанные с себестоимостью документы. При попытке записи элемента справочника или проведения документа система выдает критическую ошибку: «Конфликт блокировок транзакций. Превышено максимальное время ожидания предоставления блокировки».
Давайте подробно разберем, почему возникает эта проблема, как на нее влияют обновления конфигурации и какие практические шаги помогут настроить параллельную работу пользователей без остановки бизнес-процессов.
Для начала проанализируем архитектуру работы базы данных в момент расчета себестоимости. Конфигурация 1С:УПП 1.3 исторически разрабатывалась в режиме автоматических блокировок данных. В этом режиме управление блокировками таблиц полностью перекладывается на систему управления базами данных (СУБД), например, MS SQL Server или PostgreSQL.
Когда мы запускаем стандартное проведение документа «Расчет себестоимости выпуска», платформа открывает одну гигантскую транзакцию, внутри которой выполняются миллионы математических расчетов, корректировок регистров и запросов. СУБД, стремясь обеспечить максимальную согласованность данных (уровень изоляции транзакций Repeatable Read или Serializable), начинает накладывать блокировки на все считываемые и изменяемые таблицы.
В процессе работы возникают два ключевых фактора:
_Consts. Другой пользователь, пытаясь провести свой документ, пытается обновить или прочитать ту же таблицу, натыкается на блокировку РСВ, ожидает 20 секунд и отваливается по таймауту.Часто ИТ-службы замечают, что на старых релизах УПП (например, 1.3.113.4) расчет себестоимости позволял пользователям работать в фоне, а после обновления на более свежий релиз (например, 1.3.122.2) база начинает намертво зависать. Это связано с развитием конфигурации:
С каждым новым релизом разработчики внедряют в УПП новые подсистемы Библиотеки стандартных подсистем (БСП). В новых версиях БСП существенно усложнился механизм инициализации сеанса пользователя и проверки его прав. Теперь при записи любого справочника (например, «Серии номенклатуры») или проведении документа запускается цепочка подписок на события, которая считывает десятки новых констант и параметров сеанса. Поверхность пересечения блокировок между расчетом себестоимости и действиями обычных пользователей увеличилась во много раз.
Самый быстрый и эффективный способ вернуть пользователям возможность работать во время расчета себестоимости — задействовать штатную настройку самого документа РСВ. Давайте разберем этот механизм.
В документе «Расчет себестоимости выпуска» предусмотрена специальная настройка — флаг (кнопка в меню «Действия») «Провести вне транзакции». По умолчанию, если эта настройка отключена, весь расчет выполняется в одной неделимой транзакции СУБД. Если включить этот режим, логика работы кардинально меняется:
COMMIT), а все наложенные СУБД блокировки немедленно снимаются.Важное ограничение: При использовании режима проведения вне транзакции категорически запрещается изменять и проводить документы задним числом в том периоде, за который рассчитывается себестоимость. Это приведет к искажению итогов. Однако работать в текущем (открытом) периоде менеджеры и операторы смогут совершенно свободно.
Если в системе используются самописные документы, необходимо убедиться, что они не провоцируют дополнительные блокировки при чтении констант. Проанализируем пример неоптимального кода, который часто встречается в доработках:
// Неоптимальный код: прямое обращение к константе в транзакции проведения
Если Константы.ИспользоватьЛимитыОстатков.Получить() Тогда
// Выполнение логики проверки лимитов
КонецЕсли;
Такой код заставляет платформу делать прямой SQL-запрос к таблице констант внутри транзакции проведения документа. Если в этот момент выполняется РСВ, велика вероятность получить блокировку. Давайте перепишем этот фрагмент, используя механизм повторного использования значений общего модуля (кэширование):
// Оптимальный код: чтение значения из кэшированного общего модуля
ИспользоватьЛимиты = МойОбщийМодульПовторногоИспользования.ПолучитьИспользоватьЛимитыОстатков();
Если ИспользоватьЛимиты Тогда
// Выполнение логики проверки лимитов
КонецЕсли;
При таком подходе значение константы считывается из базы данных всего один раз при первом обращении, а затем хранится в оперативной памяти сеанса пользователя. Это полностью исключает лишние SQL-запросы к заблокированной таблице констант.
Если ваша база данных существенно доработана, хорошим решением будет точечный перевод самописных документов и критически важных регистров на управляемый режим блокировок. Это позволит вам вручную указывать платформе, какие именно данные нужно заблокировать, не полагаясь на избыточные автоматические блокировки СУБД.
Давайте посмотрим, как программно заблокировать только конкретный диапазон данных перед записью в регистр накопления, избегая блокировки всей таблицы:
// Программная установка управляемой блокировки
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.УчетЗатратРегламентированный");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
// Блокируем данные только по конкретной организации и периоду
ЭлементБлокировки.УстановитьЗначение("Организация", СсылкаНаОбъект.Организация);
ЭлементБлокировки.УстановитьЗначение("Период", Новый Диапазон(НачалоМесяца(Дата), КонецМесяца(Дата)));
Блокировка.Заблокировать();
Использование этого кода гарантирует, что транзакция вашего документа заблокирует только данные по конкретной организации за определенный месяц. Все остальные записи регистра останутся доступными для параллельной работы других процессов, включая расчет себестоимости.
Чтобы со стопроцентной точностью определить, какая именно строка кода или таблица СУБД выступает инициатором блокировки, необходимо настроить сбор технологического журнала на сервере «1С:Предприятие». Создадим файл конфигурации logcfg.xml в каталоге установки платформы со следующим содержимым:
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="C:\v8\logs\locks" history="24">
<event>
<eq property="Name" value="TTIMEOUT"/>
</event>
<event>
<eq property="Name" value="TLOCK"/>
</event>
<property name="all"/>
</log>
</config>
Проанализировав файлы логов после возникновения ошибки «Конфликт блокировок транзакций», мы увидим точные имена таблиц базы данных (например, _InfoRegXXXX или _Consts) и контекст исполнения на встроенном языке 1С, который привел к ожиданию и сбою.
При записи движений документов СУБД часто блокирует таблицы итогов регистров накопления. Чтобы минимизировать эти конфликты, необходимо зайти в конфигуратор и проверить свойства наиболее активно используемых регистров (особенно тех, в которые делает движения ваш самописный документ).
Убедимся, что на вкладке «Данные» у этих регистров установлен флаг «Разделение итогов». Данный механизм позволяет платформе записывать движения разных транзакций во временные независимые таблицы дельт, объединяя их позже в фоновом режиме. Это значительно снижает вероятность взаимных блокировок при одновременной работе пользователей и расчета себестоимости.
Для минимизации конфликтов во время проведения РСВ рекомендуется придерживаться следующих правил: