При работе в конфигурации 1С:Управление торговлей 10.3 или других системах на платформе 1С программисты часто сталкиваются с крайне неинформативным сообщением: «В данной транзакции уже происходили ошибки». Эта ситуация возникает в момент записи объекта (например, контрагента) и ставит в тупик, так как само сообщение не указывает на истинную причину проблемы. В этой статье мы подробно разберем, почему возникает это состояние и как найти «виновника» программного сбоя.
Прежде чем переходить к практике, нам важно понять внутреннюю логику работы платформы 1С. Когда вы вызываете метод Записать() или нажимаете кнопку «ОК» в форме, система открывает транзакцию. Транзакция — это неделимая последовательность действий с базой данных. Если внутри этой последовательности происходит любая ошибка (например, нарушение прав доступа RLS, ошибка в коде или блокировка), платформа выставляет внутренний флаг состояния транзакции в значение «Ошибка».
Проблема заключается в том, что даже если вы обернули проблемный участок кода в блок Попытка...Исключение, транзакция уже считается «битой». Любая последующая попытка записи в базу данных в рамках этой же транзакции или попытка её завершить (ЗафиксироватьТранзакцию()) приведет к тому самому сообщению о том, что в транзакции уже происходили ошибки. Платформа просто не позволяет зафиксировать данные, которые могут быть неконсистентными из-за первого произошедшего сбоя.
Выясним причину первой, скрытой ошибки. Самый быстрый способ сделать это — настроить отладчик так, чтобы он останавливался именно в тот момент, когда происходит первое исключение, а не тогда, когда система выдает итоговое сообщение.
Теперь отладчик остановится на той строке, где возникла самая первая проблема (например, деление на ноль или попытка записи в несуществующий реквизит), которая «отравила» транзакцию.
Рассмотрим ситуацию, когда код перегружен конструкциями Попытка...Исключение, как в примере из сообщения автора темы:
Попытка
ЗаписатьВФорме();
Исключение
ОбщегоНазначения.СообщитьОбОшибке(ОписаниеОшибки(),, "Элемент не записан!");
ОсновнойДоговорКонтрагента = Справочники.ДоговорыКонтрагентов.ПустаяСсылка();
Отказ = Истина;
КонецПопытки;
В данном случае блок Попытка поглощает описание реальной ошибки. Чтобы увидеть истинный текст сообщения, проанализируем совет из обсуждения: временно закомментируйте блок Попытка и КонецПопытки. Когда код выполнится без «страховки», система выдаст стандартное окно с описанием конкретной ошибки и кнопкой «Подробно», где будет указан модуль и номер строки.
Проанализируем ситуацию глубже. В УТ 10.3 запись контрагента — это сложный процесс. Ошибка может возникать не в самом модуле объекта «Контрагент», а в так называемых «Подписках на события». Например, при записи контрагента может срабатывать подписка, которая автоматически создает запись в регистре сведений или проверяет заполнение контактной информации.
Если в такой подписке происходит сбой, транзакция помечается ошибочной. Проверьте через поиск в конфигурации все подписки на события ПередЗаписью и ПриЗаписи для справочника Контрагенты. Часто проблема кроется в коде, который пытается записать связанные данные (например, ДоговорыКонтрагентов) в той же транзакции.
Важно помнить, что в 1С нет полноценных вложенных транзакций. Если вы программно вызываете НачатьТранзакцию(), находясь уже внутри процесса записи (который сам по себе является транзакцией), система просто увеличивает счетчик уровня вложенности. Рассмотрим пример:
// Где-то в глубине кода подписки на событие
НачатьТранзакцию();
Попытка
// Какое-то действие
ОтменитьТранзакцию(); // Это действие сделает ВСЮ внешнюю транзакцию невалидной!
Исключение
// Обработка
КонецПопытки;
Если во вложенном блоке был вызван метод ОтменитьТранзакцию(), то внешняя транзакция (запись контрагента) уже никогда не сможет быть зафиксирована успешно. Посмотрите на стек вызовов в отладчике, чтобы понять, на каком уровне происходит вызов отмены.
Если отладчик не помогает (например, ошибка возникает только на сервере или в фоновом задании), воспользуемся самым мощным инструментом — Технологическим журналом. Нам нужно настроить сбор событий EXCP (Exceptions). В файле настроек logcfg.xml можно указать фильтр, чтобы отловить момент возникновения исключения непосредственно перед появлением ошибки транзакции.
В логах ТЖ вы увидите текст исходной ошибки, например: "Ошибка СУБД: Взаимоблокировка" или "Конфликт блокировок". Это позволит понять, является ли проблема программной ошибкой в коде или это ограничение на уровне SQL-сервера.
Чтобы не сталкиваться с подобными ситуациями, придерживайтесь следующих правил:
Исключение обязательно делайте ВызватьИсключение или устанавливайте Отказ = Истина, не пытаясь продолжать запись других данных в базу в этой же итерации.Record Level Security.Следование этим шагам позволит вам быстро локализовать место возникновения проблемы и устранить её, сохранив стабильность работы информационной системы.