При разработке на платформе 1С:Предприятие многие сталкивались с неприятным сообщением: «В данной транзакции уже происходили ошибки!». Часто это сбивает с толку, так как сообщение появляется не в том месте, где произошел реальный сбой. Давайте разберемся, почему так происходит и как эффективно найти источник проблемы.
Важно помнить, что данное сообщение — это вторичная ошибка. Она не указывает на конкретную строку кода, которая вызвала сбой. Она лишь информирует вас о том, что вы находитесь внутри блока транзакции (между НачатьТранзакцию() и ЗафиксироватьТранзакцию()), которая была «испорчена» предыдущим исключением. Как только в транзакции возникла любая критическая ошибка, она становится неактивной, и любые последующие обращения к базе данных в рамках этого же блока будут вызывать этот системный отказ.
Чтобы найти истинную причину, необходимо действовать системно. Рассмотрим шаги, которые помогут локализовать проблему:
ПолучитьОбъект(), обращении к несуществующим ссылкам или ошибках самого запроса.Рассмотрим случай, когда ошибка возникает из-за двусмысленности в тексте запроса. Если таблица и поле называются одинаково, платформа может выдать ошибку выполнения. Исправим это, используя псевдонимы:
// Исходный проблемный запрос
Запрос.Текст = "ВЫБРАТЬ Первые 1
| Номенклатура.Ссылка КАК Номенклатура
| ИЗ Справочник.Номенклатура КАК Номенклатура
| ГДЕ Номенклатура.Наименование = &Наименование";
// Исправленный вариант с использованием псевдонима
Запрос.Текст = "ВЫБРАТЬ Первые 1
| спрНоменклатура.Ссылка КАК Номенклатура
| ИЗ Справочник.Номенклатура КАК спрНоменклатура
| ГДЕ спрНоменклатура.Наименование = &Наименование
| И НЕ спрНоменклатура.ПометкаУдаления
| И НЕ спрНоменклатура.ЭтоГруппа";
Одной из частых ошибок является подавление исключений без отмены транзакции. Если вы используете конструкцию Попытка...Исключение, вы обязаны корректно завершить работу с транзакцией. Если в блоке Исключение транзакция не отменяется, она остается в «битом» состоянии.
Рассмотрим правильный шаблон обработки:
Попытка
НачатьТранзакцию();
// Ваши операции с БД (запись, проведение)
ЗафиксироватьТранзакцию();
Исключение
Если ТранзакцияАктивна() Тогда
ОтменитьТранзакцию();
КонецЕсли;
// Обязательно выводим информацию об ошибке в журнал или пользователю
ЗаписьЖурналаРегистрации("Ошибка транзакции", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
ВызватьИсключение;
КонецПопытки;
ЗначениеЗаполнено() или Ссылка.ПустаяСсылка() перед тем, как выполнять ПолучитьОбъект().Исключение пустым. Это лишает вас возможности понять, почему система работает неверно.УникальныйИдентификатор всегда убеждайтесь, что переданная строка содержит корректный UUID, иначе вызов конструктора приведет к исключению.Проанализировав описанные методы, вы сможете быстрее находить узкие места в своем коде. Главное правило: не пытайтесь «лечить» симптомы, всегда ищите первый источник исключения, который перевел транзакцию в нерабочее состояние.