Ошибка с текстом «В данной транзакции уже происходили ошибки» является одной из самых коварных в платформе «1С:Предприятие 8». Ее коварство заключается в том, что это сообщение — лишь «эхо» настоящей проблемы. Платформа сообщает нам не о том, что именно сломалось, а о том, что база данных находится в состоянии, когда дальнейшая работа внутри текущей транзакции невозможна.
В этой статье мы подробно разберем природу этого явления, проанализируем различные сценарии возникновения ошибки на основе реального опыта разработчиков и выработаем пошаговый алгоритм диагностики и лечения вашей базы данных.
Для начала выясним причину возникновения такой формулировки. В 1С любая запись объекта (справочника, документа) происходит внутри транзакции — последовательности действий, которые должны быть выполнены либо полностью, либо не выполнены вовсе. Если в процессе выполнения этой последовательности (например, в блоке Попытка...Исключение) произошел какой-то сбой, СУБД (MS SQL Server, PostgreSQL или файловый движок) помечает транзакцию как «битую» (отравленную). С этого момента любое следующее обращение к базе данных внутри этого же кода вызовет наше злополучное сообщение.
Транзакция требует немедленного отката через ОтменитьТранзакцию(), но если программный код пытается двигаться дальше и снова вызвать метод Записать() или обратиться к константе, платформа выдает ошибку. Наша задача — найти тот самый «первый сбой», который произошел за доли секунды до появления окна с сообщением.
Рассмотрим ситуацию, с которой столкнулся автор темы. Проблема возникла после обновления конфигурации и проявлялась при попытке изменить контактную информацию контрагента. Как выяснилось, причиной стали неактуальные правила обмена (например, с «1С:УНФ» или «1С:УТ»), которые когда-то были настроены, но давно не использовались.
Проанализируем алгоритм действий в этом случае:
Разберем еще одну частую причину — переполнение нумерации кодов. Если в справочнике (например, «Единицы измерения», «Контрагенты» или «Номенклатура») закончились свободные номера или в коде появились символы, мешающие автонумерации, запись объекта внутри транзакции сорвется.
Посмотрим на пример: система пытается автоматически назначить новый код, но из-за некорректного префикса или достижения предела разрядности (например, код «999» при длине 3) возникает внутренняя ошибка. Поскольку запись часто обернута в программные проверки, вы видите только итог — сообщение о транзакции. Решение: проверьте последний введенный код в справочнике и при необходимости перенумеруйте его или увеличьте длину кода в конфигураторе.
Иногда ошибка проявляется только у пользователей с ограниченными правами. Выясним причину: механизмы RLS (разграничение прав на уровне записей) могут использовать сложные запросы при записи объекта. Если у пользователя нет прав на какой-то вспомогательный регистр (например, ВерсииОбъектов или ЗаданияКРаспределениюРасчетов), транзакция «травится» именно в момент проверки прав.
Рассмотрим порядок диагностики:
ПриЗаписи.Если стандартная отладка не помогает и «Тестирование и исправление» не находит ошибок в структуре БД, нам необходимо настроить Технологический журнал (ТЖ). Это единственный способ увидеть самую первую ошибку (исключение), которая произошла в системе.
Создадим файл logcfg.xml в каталоге настроек сервера 1С и добавим в него сбор событий EXCP. Посмотрим на пример конфигурации файла:
<config xmlns="http://v8.1c.ru/7.4/get/logcfg">
<log location="C:\LOGS\EXCP" history="24">
<event>
<eq property="Name" value="EXCP"/>
</event>
<property name="all"/>
</log>
</config>
После возникновения ошибки проанализируем текстовые файлы логов. Ищите записи, которые предшествуют строке «В данной транзакции уже происходили ошибки». Там может быть скрыта реальная причина: например, Violation of PRIMARY KEY constraint (нарушение уникальности) или Deadlock victim (взаимоблокировка в SQL).
В некоторых случаях проблема кроется не в коде, а в окружении. Рассмотрим технические методы «лечения» со стороны системного администрирования:
ragent.Если вы являетесь разработчиком, проанализируйте свой код. Типичная ошибка — попытка вызвать исключение внутри транзакции без ее корректного завершения. Рассмотрим правильный и неправильный варианты.
Неправильно:
НачатьТранзакцию();
Попытка
Объект.Записать();
Исключение
// Здесь произошла ошибка СУБД, транзакция "сломана"
Сообщить(ОписаниеОшибки());
// Пытаемся записать что-то еще в этой же транзакции
ДругойОбъект.Записать(); // Вот здесь вылетит "В данной транзакции..."
КонецПопытки;
ЗафиксироватьТранзакцию();
Правильно:
НачатьТранзакцию();
Попытка
Объект.Записать();
ЗафиксироватьТранзакцию();
Исключение
Если ТранзакцияАктивна() Тогда
ОтменитьТранзакцию();
КонецЕсли;
Сообщить("Ошибка записи: " + ОписаниеОшибки());
КонецПопытки;
Мы выяснили, что ошибка транзакции — это лишь симптом. Чтобы вылечить «пациента», следуйте этому чек-листу:
EXCP).Помните, что платформа 1С версии 8.2 и 8.3 крайне чувствительна к целостности транзакционного цикла. Соблюдение правил работы с блоками Попытка...Исключение и своевременная очистка базы от устаревших правил интеграции помогут избежать подобных «экзотических» проблем в будущем.