Команда "ЗафискироватьТранзакцию();" отменяет транзакцию

26.03.19

Разработка - Механизмы платформы 1С

Когда "ЗафискироватьТранзакцию();" отменяет транзакцию. Делюсь опытом эксплуатации.

Функция создания заказа была написана по стандартам разработки.

Упрощенный пример:

Функция СоздатьЗаказ(ВнешнийНомер)

    НачатьТранзакцию();
    Попытка

        ДокументЗаказ = Документы.Заказы.СоздатьДокумент();
    
        ДокументЗаказ.ВнешнийНомер = ВнешнийНомер;

        ДокументЗаказ.Записать(РежимЗаписиДокумента.Проведение);

        ЗафиксироватьТранзакцию();
    Исключение
        ОтменитьТранзакцию();

        Возврат "Ошибка создания заказа";
    КонецПопытки;

    Возврат ДокументЗаказ.Номер;

КонецФункции


С очередным обновлением внутри документа заказа появилась доработка с ошибкой и одновременно написанная с нарушением стандарта разработки.
В модуле документа заказа.

Процедура ОбработкаПроведения()

    ....

    //Последняя доработка в конце
    Попытка

        ...запись в базу с ошибкой

    Исключение
        //по стандарту должно быть исключение, т.к. есть внешняя транзакция 
        //но его не было
        //ВызватьИсключение; 
    КонецПопытки;

КонецПроцедуры

В результате, до обнаружения и исправления ошибки, довольно продолжительное время функция создания заказа успешно делал вид, что создает заказы и возвращала контрагентам какие-то номера.

В базе документы не появлялись.

На первый взгляд кажется, что функция создания заказа (она ведь по стандартам) рассчитана на ошибки внутри вложенных транзакций и на команде "ЗафиксироватьТранзакцию();" должна выдать до боли знакомое сообщение "В этой транзакции уже происходили ошибки!". 

На практике функция возвращала номера как-будто создаваемых заказов!

 

Рассмотрим документацию на сайте "its.1c.ru".

В стандартах разработки в главе "Транзакции: правила использования (Новый раздел!)" почему то нет описания этого момента.

 

Ответ все-таки есть, но в разделе методической поддержки в главе "Вложенность транзакций".

Отрывок с сайта "its.1c.ru" (ссылка выше):

"При вызове отмены вложенной транзакции (явно или в результате произошедшего исключения) запоминается факт, что одна из вложенных транзакций была отменена (реального отката транзакции в этот момент не происходит), что приводит к невозможности фиксации результатов транзакции верхнего уровня. При этом, при попытке фиксации транзакции верхнего уровня никаких исключений выдано не будет. Просто вся транзакция завершится откатом. Соответственно, все изменения базы данных, произведенные в рамках транзакции верхнего уровня, будут отменены."

Вот и ответ, транзакция отменена, данные в базу не записаны, но это не вызывает исключения!!!

 

В свою очередь ошибка "В этой транзакции уже происходили ошибки!" возникает не на команде "ЗафискироватьТранзакцию();", а при первом обращении к базе (как при чтении, так и при записи) после отмены вложенной транзакции.

 

В нашем случае доработка была добавлена именно в конце модуля проведения, что в общем-то естественно, и обращений к базе больше не было.

 

Выводы и пожелания:
1. Хотелось бы в стандартах разработки на ИТС увидеть решение, более устойчивое к ошибкам в глубине стэка. 

Например, перед командой "ЗафискироватьТранзакцию();" выполнять запрос к базе данных "Выбрать 1" для гарантированного вызова исключения "В этой транзакции уже происходили ошибки!".

Другой вариант это проверять, что ссылка "созданного" документа не пустая (ссылка объекта очищается при отмене транзакции).

2. Хотелось бы, чтобы когда-нибудь в будущем при отмене транзакции командой "ЗафискироватьТранзакцию();" вызывалось исключение.

ЗафискироватьТранзакцию транзакция стандарт разработка эксплуатация

См. также

Сервисы интеграции без Шины и интеграции

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    2635    dsdred    16    

59

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Обмен между базами 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    6088    dsdred    59    

86

Как готовить и есть массивы

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    5984    YA_418728146    25    

68

Планы обмена VS История данных

Обмен между базами 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    7087    dsdred    36    

113

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    19191    SeiOkami    46    

118

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    12907    human_new    27    

76

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    9516    YA_418728146    6    

143

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6567    sebekerga    54    

95
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. tormozit 7143 26.03.19 08:50 Сейчас в теме
Если ЗафиксироватьТранзакцию() станет выбрасывать исключение при установленном признаке отмены транзакции (сломанная транзакция), то придется во всех существующих конфигурациях в большом числе мест заменить ЗафиксироватьТранзакцию() на
Если ВТранзакцииПроисходилиОшибки() Тогда
    ОтменитьТранзакцию();
Иначе
    ЗафиксироватьТранзакцию();
КонецЕсли;
т.к. далеко не все выбросы исключений станут полезными. А точнее большинство из них станут вредными, т.к. существующее поведение документировано и на него опирались программисты при написании кода. Определение функции ВТранзакцииПроисходилиОшибки() смотри в статье https://infostart.ru/public/1026771/ . В этой же статье показано, что метод ЗафиксироватьТранзакцию() при глубине = 1 не всегда фиксирует фактическую транзакцию, а закрывает ее путем отката если она сломана и путем фиксации если она не сломана. Поэтому правильнее было бы назвать его ЗакрытьТранзакцию(). А вот метод ОтменитьТранзакцию() имеет более правильное название, т.к. при глубине =1 всегда отменяет фактическую транзакцию.
kuzyara; Pipapalamm; +2 Ответить
2. bulpi 215 26.03.19 14:17 Сейчас в теме
(1)
Так то оно так. Но из статьи следует, что стандарт неустойчив по отношению к вложенным ошибкам. Что-то надо менять.
4. rinat_alp2 61 26.03.19 18:56 Сейчас в теме
(1) Вы правы, что поведение платформы лучше не менять и оставлять обратную совместимость.
Хорошая идея сделать новую команду.
5. rinat_alp2 61 27.03.19 07:39 Сейчас в теме
(1)
далеко не все выбросы исключений станут полезными. А точнее большинство из них станут вредными, т.к. существующее поведение документировано и на него опирались программисты при написании кода.


У Вас шикарная статья, в том числе описывающая проблему, с которой я столкнулся.
Если Вы не против я подискутирую про приведенную выше цитату.

По моему мнению, если разработчик хочет отменить изменения он использует "ОтменитьТранзакцию();", а если потеря данных происходит в любом другом явно не указанном случае, то это ошибка, которую нельзя прятать и должно быть исключение.
6. tormozit 7143 27.03.19 09:19 Сейчас в теме
(5) Я согласен, что если бы был правильный метод ЗафиксироватьТранзакциюОбязательно(), который бы выбрасывал исключение при установленном признаке отмены транзакции и о котором бы все знали, то во многих случаях разработчики применяли бы его для фиксации транзакции и это подняло бы качество кода.
Но менять логику работы уже используемого в огромном количестве кода метода слишком опасно, т.к. программисты могли как явно так и неявно опираться на эти нелогичные особенности его текущей реализации и тем самым обеспечивать корректную логику работы их программы.
В итоге я предлагаю использовать для борьбы со скрытой отменой/откатом транзакции собственный метод
Процедура ЗафиксироватьТранзакциюОбязательно() Экспорт 
	Если ВТранзакцииПроисходилиОшибки() Тогда
		ВызватьИсключение "В данной транзакции уже происходили ошибки";
	Иначе
		ЗафиксироватьТранзакцию();
	КонецЕсли; 
КонецПроцедуры

Добавил его в статью в раздел "Скрытая отмена транзакции".
В платформе же я бы предложил добавить параметр "Обязательно" в метод ЗафиксироватьТранзакцию, при установке которого бы выбрасывалось исключение, а по умолчанию он естественно равен Ложь для обеспечения совместимости. Тогда наверное и не будет смысла его переименовывать.
A_Max; rinat_alp2; +2 Ответить
3. sergathome 4 26.03.19 14:28 Сейчас в теме
В текущей парадигме вложенность транзакций вообще не имеет смысла. Было бы логично увидеть это в стандарте, однако там опять какая-то лапша про вложенность, уровни и тп. Детский сад, вторая четверть...:( Какая может быть вложенность при том, что даже синхронный * не гарантируется ! Реально в транзакции может произойти одна ошибка и транзакция не будет откачена, хотя при второй откачена будет гарантированно (ну, с воплем "ошибки уже происходили"). В мануале же на эту тему опять какая-то лапша про уровни серьёзности ошибок...

зы прикольно, движок инфостарта считает слово ОТКАТ неприличным
7. kuzyara 1914 29.03.19 08:50 Сейчас в теме
ЗафиксироватьТранзакциюОбязательноВоЧтоБыТоНеСталоВоИмяБорис­аНуралива() ;)
8. user1031959 08.05.19 17:03 Сейчас в теме
У вас вообще с логикой проблемы, товарищ. После того как вы вываливаетесь в исключение, что вы пытаетесь вернуть далее? Номер какого документа?

Вот пример как делал недавно я:

	
        ОшибкиЗаписи = Ложь;
	НачатьТранзакцию();
	
	Для Каждого ТекСтрока Из Объект.Платежи Цикл
		
		// СОЗДАЕМ ДОК. ОПЛАТА ПЛАТЕЖНОЙ КАРТОЙ
		НоваяОплатаПК = Документы.ОплатаПлатежнойКартой.СоздатьДокумент();
		
		НоваяОплатаПК.Дата 					= ТекСтрока.ДатаПеревода;

                // и т.д.		
		
		// Запись документ "Операция по платежной карте"
		Попытка
		    НоваяОплатаПК.Записать(РежимЗаписиДокумента.Проведение);					
		Исключение
			Сообщить(ОписаниеОшибки());
			Если ТранзакцияАктивна() Тогда
				ОтменитьТранзакцию();
			КонецЕсли;
			Прервать;
		КонецПопытки;
		
		// СОЗДАЕМ ДОК. ПОСТУПЛЕНИЕ НА Р/С
		
		НовоеПоступление = Документы.ПоступлениеНаРасчетныйСчет.СоздатьДокумент();
		НовоеПоступление.Заполнить(НоваяОплатаПК.Ссылка);
		НовоеПоступление.НазначениеПлатежа = Объект.Назначение;
		НовоеПоступление.Дата = НоваяОплатаПК.Ссылка.Дата;
		Попытка
			НовоеПоступление.Записать(РежимЗаписиДокумента.Проведение);
		Исключение
			Сообщить(ОписаниеОшибки());
			Если ТранзакцияАктивна() Тогда
				ОтменитьТранзакцию();
			КонецЕсли;
			Прервать;
		КонецПопытки;
	
	КонецЦикла;
	
	Если ТранзакцияАктивна() Тогда
		ЗафиксироватьТранзакцию();
		Сообщить("Документы успешно записаны");
	КонецЕсли; 
Показать


Вот статья по работе с транзакциями:
https://habr.com/ru/post/419715/
11. rinat_alp2 61 28.04.23 09:43 Сейчас в теме
(8) В исключении возврат, если бы исключение сработало, тогда обращения к объекту бы не было.
 
   Исключение
        ОтменитьТранзакцию();

        Возврат "Ошибка создания заказа";
    КонецПопытки;
9. kuzyara 1914 18.12.19 10:43 Сейчас в теме
Если же при значении счетчика траназкций большем 1 произойдет обращение к методу ОтменитьТранзакцию(), то значение счетчика транзакций не только будет уменьшено на 1, но и произойдет установка признака, не позволяющего зафиксировать результаты выполнения всей транзакции в целом. И последующее обращение к методу ЗафиксироватьТранзакцию(), выполняемое при значении счетчика транзакций равном 1, фактически приведет к отмене транзакции:
https://its.1c.ru/db/metod8dev#content:2313:hdoc
Оставьте свое сообщение