В процессе многопользовательской работы в системах на базе 1С:Предприятие 8.3 программисты и системные администраторы часто сталкиваются с критической ошибкой: "Конфликт блокировок при выполнении транзакции". Эта проблема напрямую влияет на производительность бизнеса, препятствуя одновременной работе пользователей с документами и справочниками. В рамках данной статьи мы подробно проанализируем причины возникновения этой ошибки и разберем по шагам эффективные методы её устранения.
Для начала разберем, почему возникают блокировки. В 1С существует два основных режима управления блокировками: автоматический и управляемый. В автоматическом режиме за блокировки отвечает СУБД (например, MS SQL Server), которая часто блокирует целые таблицы вместо конкретных строк, что и приводит к конфликтам. В современных конфигурациях используется Управляемый режим, где разработчик сам указывает, какие данные нужно заблокировать перед чтением или записью.
Рассмотрим подробнее механизм возникновения Deadlock (взаимоблокировки). Ситуация возникает, когда первая транзакция захватывает Объект А и ждет доступа к Объекту Б, в то время как вторая транзакция захватила Объект Б и ожидает доступа к Объекту А. Проанализируем ситуацию: система не может продолжать работу, и одна из транзакций аварийно завершается платформой.
Первым делом проанализируем код запросов. Основной причиной избыточных блокировок является чтение данных внутри транзакции без явного указания цели. Если мы читаем данные для последующего изменения, мы должны использовать объект БлокировкаДанных.
Разберем по шагам, как правильно установить управляемую блокировку в коде 1С:
БлокировкаДанных.РегистрНакопления.ЗапасыНаСкладах).Склад или Номенклатура), чтобы заблокировать только нужные записи, а не весь регистр.Заблокировать().Посмотрим на пример кода, реализующего этот механизм:
ЭлементБлокировки = Новый БлокировкаДанных;
Блок = ЭлементБлокировки.Добавить("РегистрНакопления.ОстаткиТоваров");
Блок.Режим = РежимБлокировкиДанных.Исключительный;
Блок.УстановитьЗначение("Склад", СсылкаНаСклад);
Блок.ИсточникДанных = ТаблицаТоваров;
Блок.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
ЭлементБлокировки.Заблокировать();
Использование этого метода позволяет нам значительно повысить параллельность работы, так как другие пользователи смогут записывать данные по другим складам без ожидания.
Проанализируем работу планировщика SQL-запросов. При использовании сложных вложенных запросов СУБД может неверно построить план выполнения, что приводит к блокировке лишних индексов. Посмотрим на пример оптимизации через использование объекта МенеджерВременныхТаблиц.
Рассмотрим подробнее преимущества временных таблиц:
Пример использования ВременнаяТаблица в запросе:
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| ТЧ.Номенклатура КАК Номенклатура,
| СУММА(ТЧ.Количество) КАК Количество
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| &ТаблицаТоваров КАК ТЧ
|СГРУППИРОВАТЬ ПО
| ТЧ.Номенклатура
|;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ.Номенклатура,
| ВТ.Количество,
| ЕСТЬNULL(Остатки.ВНаличииОстаток, 0) КАК Остаток
|ИЗ
| ВТ_Товары КАК ВТ
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Запасы.Остатки(,&Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ВТ_Товары)) КАК Остатки
| ПО ВТ.Номенклатура = Остатки.Номенклатура";
Запрос.УстановитьПараметр("ТаблицаТоваров", Объект.Товары.Выгрузить());
Результат = Запрос.Выполнить();
Выясним причину классического Deadlock. Если один процесс сначала обновляет Справочник.Склады, а затем РегистрНакопления.Запасы, а второй процесс делает это в обратном порядке — блокировка неизбежна.
Разберем правило, которое поможет избежать этой ситуации: всегда обращайтесь к объектам метаданных в строго определенном порядке (по алфавиту или по иерархии). Если во всех участках кода запись в регистры происходит в одной и той же последовательности, транзакции будут выстраиваться в очередь, а не блокировать друг друга навсегда.
Также важно минимизировать время нахождения в транзакции. Рассмотрим рекомендации:
Записать().ЗафиксироватьТранзакцию() чаще.Если программные методы не помогают, проанализируем ситуацию с помощью системных инструментов. Технологический журнал 1С позволяет точно определить, какой именно кусок кода вызвал блокировку и какой процесс был "жертвой".
Для настройки ТЖ необходимо создать файл logcfg.xml и добавить в него событие TLOCK (Transaction Lock). Посмотрим на структуру настройки:
<config xmlns="http://v8.1c.ru/7.4/get/logcfg">
<log location="C:\LOGS\LOCKS" history="24">
<event>
<eq property="name" value="TLOCK"/>
</event>
<property name="all"/>
</log>
</config>
После сбора логов мы сможем увидеть WaitConnections — номера сеансов, которые мешают друг другу. Проанализировав этот список, мы найдем конкретные строки кода в конфигураторе, требующие оптимизации.
Важный момент: не забывайте отключать логирование после завершения анализа, так как файлы журнала могут занимать значительный объем дискового пространства.
Мы рассмотрели основные методики борьбы с блокировками в 1С 8.3. Подведем итог: во-первых, всегда используйте управляемый режим блокировок. Во-вторых, оптимизируйте запросы, избавляясь от подзапросов в пользу МенеджерВременныхТаблиц. В-третьих, следите за порядком захвата ресурсов в транзакциях. Применяя эти правила системно, мы сможем добиться стабильной работы базы данных даже при очень высокой интенсивности ввода документов.