четверг, 22 октября 2015 г.

В данной транзакции уже происходили ошибки или попытка не пытка.


Рано или поздно каждому программисту 1с придется познакомится с сообщением об ошибке "В данной транзакции уже происходили ошибки".
В этой статье разберем природу этой ошибки.
Данная ошибка появляется при использовании конструкции Попытка... Исключение внутри транзакции. Дело в том, что если  исключительную ситуацию отрабатывать с помощью скобок Попытка...Исключение...КонецПопытки, расположенных внутри транзакции, то транзакция не завершится в момент возникновения исключительной ситуации, она дойдет до следующего обращения к данным — чтения или записи, продолжая при этом блокировать ресурсы, и откатится с сообщением: «В данной транзакции уже происходили ошибки!». 

НачатьТранзакцию();
//первая попытка
Попытка
Исключение
КонецПопытки;

//вторая попытка
Попытка
Исключение
КонецПопытки;

РезультатЗапроса = Запрос.Выполнить();
ЗафиксироватьТранзакцию();

В  схеме описанной выше ошибка возникнет в строке РезультатЗапроса = Запрос.Выполнить();
Первая неприятность заключается в том, что совершенно не понятно в какой из попыток выше приключилась ошибка, что затрудняет ее поиск и исправление ведь зачастую ОписаниеОшибки()  ничего не сообщает. Вторая неприятность заключается в том, что эти сообщения не могут вызывать положительных эмоций у пользователей, которые часто спешат поделится ими с руководством, а дальше Вы сами знаете).
Таким образом использование Попытка...Исключение... КонецПопытки в транзакции никоим образом не решает наших проблем. 
Поэтому следует по возможности хорошенько подумать как избежать вообще использования попыток в транзакции. 
В моей практике был подобный случай. Фоновые задания загружали в систему заказы от контрагентов. Поначалу мы легкомысленно использовали конструкцию Попытка...Исключение... КонецПопытки. В итоге загрузка спотыкалась, заказы не загружались, все нервничали. Изменить ситуацию удалось очень тщательным предварительным разбором файла перед загрузкой и в случае проблем отправление письма клиенту и на саппорт.
Если же без попытки ни как то следует отработав исключительную ситуацию, вызывать оператор ВызватьИсключение 
Описанное поведение системы позволяет говорить о том, что если возникает ситуация, когда внутри транзакций нужно использовать скобки
Попытка...Исключение... КонецПопытки, необходимо, отработав исключительную ситуацию, вызывать оператор ВызватьИсключение. В таком случае выполнение кода завершится в конце попытки и дальше не пойдет, таким образом пользователи не увидят ошибку «В данной транзакции уже происходили ошибки!». 
Однако не всегда ошибочная ситуация приведет к появлению такой ошибки, это зависит от того восстановимая ошибка случилась или нет. Например:
Попытка
а =6/0;
Исключение
КонецПопытки;
Не приведет к появлению ошибки «В данной транзакции уже происходили ошибки!».
а вот следующий код системе не сможет "прожевать" и ошибка появится.

СпрНом = Справочники.Товары.СоздатьЭлемент();
СпрНом.Код ="000001" // товар с таким кодом уже был создан ранее
Попытка
СпрНом.Записать();
Исключение
КонецПопытки;

Также не упущу возможность развеять один миф в плену которого я и сам находился.
Миф звучит так "Попытка Исключение организует неявную транзакцию". Причем это сообщение от одного весьма известного методиста на форуме.
На самом деле это не так. Никакой неявной транзакции Попытка Исключение не организует.
Подведем итоги:
1) Крайне нежелательно использовать конструкцию Попытка...Исключение... КонецПопытки в транзакции.
2) Если уж без этого не обойтись то использование оператора ВызватьИсключение уберет появление ошибки "В данной транзакции уже происходили ошибки".




1 комментарий: