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

Публикация № 780561

Программирование - Практика программирования

10
Описан пример воспроизведения, и описание причин возникновения данной ошибки.

Собственно, сабж описан на ИТС: Ошибки базы данных и транзакции. Здесь хочу дать пример воспроизведения, и пару рекомендаций как делать "не надо"...

Создам простенькую тестовую конфу:

 
 Структура конфигурации

Теперь предположим такое пожелание: пользователь хочет, чтобы при проведении поступления ТМЦ автоматически регистрировался адрес поставщика в документе "Досье контрагента". Программист добавляет в поступление реквизит "Адрес", и пишет следующий код в модуле объекта:

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
	Попытка
		Док = Документы.ДосьеКонтрагентов.СоздатьДокумент();
		Док.Дата = ЭтотОбъект.Дата;
		Док.Контрагент = ЭтотОбъект.Поставщик;
		Док.Адрес = ЭтотОбъект.Адрес;
		Док.Записать(РежимЗаписиДокумента.Проведение);		
	Исключение
	КонецПопытки;
КонецПроцедуры

Тут надо конечно сделать поиск по ранее созданным документам, но это просто пример, я не буду углубляться. Что здесь происходит? Вложенная транзакция, которая может привести к т.н. "невосстановимой" ошибке базы данных. К примеру, если на дату записи поступления ТМЦ будут существовать записи в регистре сведений по тому же контрагенту, то произойдет дублирование по ключу измерения - это сделает невозможным проведение досье из поступления, вызвав ту самую ошибку, которой посвящена эта статья. То-же самое будет, если в самом досье в обработке проведения поставить "Отказ = Истина" - например адрес не выдержал каких-то проверок, и алгоритм досье не позволяет записывать в базу эти данные. Все, что связано с изменением данных внутри транзакции - может привести к такой ошибке.

А есть еще вторая категория ошибок - "Восстановимые". Где-то в интернете видел такой пример:

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

Попытка
	а = 1/0;
Исключение
КонецПопытки;

ЗафиксироватьТранзакцию();

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

Осталось обратить внимание на такой вопрос: а в какой именно момент возникает ошибка? Правильный ответ - при последующем чтении данных (об этом где-то рассказано на ИТС, я не могу сейчас найти статью - если кто-нибудь скинет, буду благодарен). Действительно, в ситуации на скриншоте ниже ошибка уже произошла, но терминирующего сообщения в точке останова еще нет. Оно появится когда начнет работать обработчик проведения - который первым делом считывает движения объекта, поэтому в точку останова 2 мы не попадаем:

А вот если инициировать обращение к данным базы сразу после того как произошла ошибка, мы увидим вот такое:

Надеюсь, кому-то это будет полезным - по крайней мере за 15 минут гугления, подобного описания я не встретил. Только вводящий в заблуждение пример обработки исключения внутри транзакции, о котором упоминалось выше.

Выводы:

- Непродуманная запись одних объектов внутри других - это зло. Даже если на первый взгляд все работает, небольшое изменение архитектуры может привести к проблемам. К примеру - если бы поступление ТМЦ из моего примера не делало бы никаких движений в базе, то и ошибки бы не возникло - ведь тогда бы не происходило обращения к базе после отката проведения вложенной транзакции. Но скажем, если бы это "решение" просуществовало пару месяцев, а потом потребовалось добавить движения к документу - сразу бы напоролись на сабж, в самый неподходящий момент.  С другой стороны ключи аналитики в типовых конфигурациях создаются именно так. 7 раз отмерь...

- Следует помнить что существуют две категории ошибок БД - восстановимые и невосстановимые (об этом явно сказано на ИТС, в самом начале статьи). Можно использовать попытки, в т.ч. внутри транзакции. Но следует помнить, что попытка - это по-сути тоже транзакция, ее использование тормозит систему, кроме этого затрудняет отладку (при включенной остановке на ошибках, если есть частый выброс исключения). И если уж все-таки никак без нее не обойтись, то применять ее следует правильно - ИТС: Перехват исключений в коде.

10

Скачать файлы

Наименование Файл Версия Размер
Конфигурация с воспроизведением
.cf 90,52Kb
06.02.18
0
.cf 90,52Kb Скачать

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. MSK_Step 19 06.02.18 10:57 Сейчас в теме
Просто руки кривые, код записи пишут после записи, чтобы не влиял на текущий объект.
4. unichkin 1171 06.02.18 19:12 Сейчас в теме
(1) После записи возможен только с формы, и это тоже плохой вариант, имхо.. Хоть счета-фактуры и вводятся именно так.
10. MSK_Step 19 07.02.18 12:26 Сейчас в теме
(4)
это тоже плохой вариант, имхо

Ваши аргументы, Сэр
15. unichkin 1171 07.02.18 21:37 Сейчас в теме
(10)
это тоже плохой вариант, имхо

я их привел - "ПослеЗаписи" доступно только с формы
16. MSK_Step 19 08.02.18 11:18 Сейчас в теме
(15)
я их привел - "ПослеЗаписи" доступно только с формы

Это не аргумент, значит решение не подходит под какой то ваш пример, где надо использовать модуль объекта. Хотя такие примеры надо поискать, что за велосипед изобретают .
18. unichkin 1171 08.02.18 16:22 Сейчас в теме
(16) При чем тут "какой-то мой пример"? События формы нужны для обработки интерактива. Например записи РС обновить, отображаемого в таблице формы. А когда там автоматически новый объект создается, и записывается без участия пользователя - явно какой-то архитектурный обвал.
Я хочу сказать, что если нужна такая связь между обновляемым объектом БД и текущим - она должна быть реализована в серверных обработчиках, где нет "ПослеЗаписи". А тут объекты будут синхронизироваться только по пользовательскому действию, и если программно создать объект А, из которого должен автоматически создаться объект Б - этого не произойдет при таком подходе. Потому и говорю, что плохой вариант. Синхронизации-то нет.
19. MSK_Step 19 08.02.18 17:56 Сейчас в теме
(15)
я их привел - "ПослеЗаписи" доступно только с формы

Это не аргумент, значит решение не подходит под какой то ваш пример, где надо использовать модуль объекта. Хотя такие примеры надо поискать, что за велосипед изобретают .
(18)
архитектурный обвал.

Разработчики 1с считают по другому
20. unichkin 1171 08.02.18 20:27 Сейчас в теме
(19)
Разработчики 1с считают по другому

было бы неплохо увидеть ссылку на ИТС, где они так считают. Или хотя бы место в типовой. Я знаю, счета-фактуры в полуавтомате вводятся, но там по-моему тоже не без участия пользователя это происходит. Дайте контекст посмотреть?
21. MSK_Step 19 08.02.18 23:16 Сейчас в теме
(20)не будет разводить спор, точнее я не буду. У каждого свои велосипеды))
9. herfis 282 07.02.18 11:41 Сейчас в теме
(1)
Просто скажу - что запись одного объекта внутри другого - грубейшая ошибка, так делать не надо.

А можно на пальцах для тупых, которым "просто скажу" - недостаточно? С каких-таких это грубейшая ошибка?

Вложенная транзакция, которая может привести к т.н. "невосстановимой" ошибке базы данных. К примеру, если на дату записи поступления ТМЦ будут существовать записи в регистре сведений по тому же контрагенту, то произойдет дублирование по ключу измерения - это сделает невозможным проведение досье из поступления, вызвав ту самую ошибку, которой посвящена эта статья.

Что-то я не увидел "невосстановимой" ошибки. Отмена вышестоящей транзакции при ошибке во вложенной - это именно то поведение, которое и ожидается при использовании вложенных транзакций. В чем тут "невосстановимость"?
Использовать попытки/исключения в транзакциях не обрабатывая возможные последствия - за это да, надо генные чистки производить.
Но вложенные транзакции тут причем?

ЗЫ. Бред какой-то, слово "0ткат" движок форума заменяет на звездочку. Это что, такая тупая деполитизация? *.
14. unichkin 1171 07.02.18 21:36 Сейчас в теме
(9) Про невосстановимые ошибки - ознакомьтесь с ссылкой на ИТС в начале статьи, терминология оттуда.
"С каких-таких это грубейшая ошибка? " - с таких, что если не говорим о продуманной архитектуре может произойти дикий ахтунг, причем совершенно внезапно как для автора, так и для пользователей \ или его коллег. Хотя, признаю что с формулировкой перегнул... Поправлю фразу про "грубейшую" ошибку.
17. herfis 282 08.02.18 12:32 Сейчас в теме
(14)
Про невосстановимые ошибки - ознакомьтесь с ссылкой на ИТС в начале статьи, терминология оттуда.

А! Дошло наконец! Если речь именно про ошибку "в данной транзакции уже происходили ошибки", то все верно. Она невосстановимая.
Но это последствия плохого дизайна. Меня покоробила подача, что само использование вложенных транзакций - это плохой дизайн.
А с этим я категорически не согласен. Возможность напороться при плохом дизайне - не аргумент. Плохой дизайнер всегда найдет, где напороться. А чтобы не было сабжевой ошибки достаточно просто падать сразу, вот и все.
13. acsent 1137 07.02.18 18:20 Сейчас в теме
(1) Вообще то если нужна тразанкционная целостность, то пишут в ПриЗаписи,
но таким образом мы увеличиваем само время транзакции, что не есть хорошо
2. json 06.02.18 13:27 Сейчас в теме
А в ерпи аналитика учета номенклатуры создается перед записью. Я это злом не считаю за неимением лучшего решения
3. sergathome 06.02.18 13:39 Сейчас в теме
Извините, но это, имхо, очередная кривая попытка отмазать криворуких 1с-овских разрабов, слабавших систему, на которой нельзя обрабатывать ошибки стандартным образом.

зы дадад, это не баг, это фича, ага
5. unichkin 1171 06.02.18 19:16 Сейчас в теме
Зло злу рознь)) Ключи аналитики - это исключительно служебный справочник, который не юзается пользователем в интерактивном режиме.. Одно дело когда разраб абсолютно осознанно идет на этот шаг, понимая и просчитывая последствия. Другое - когда ваяется что-то типа моего "примера".
6. strange2007 132 07.02.18 06:43 Сейчас в теме
Полностью поддерживаю - что-то создавать в момент проведения нельзя. Даже если оно сейчас работает, то потом может возникнуть куча вопросов, которые надо будет продавливать человекоденьгами. Всегда можно процесс поменять так, что этого можно избежать.
7. asved.ru 36 07.02.18 08:13 Сейчас в теме
Перевожу статью на деревенский:

Я купил лопату и отрубил ей два пальца на ноге. Лопаты - зло.


Потому что исключение нужно обрабатывать, а не глотать.
8. MSK_Step 19 07.02.18 11:01 Сейчас в теме
(7)Вряд ли тут подходит данный пример. В любом случае не запишется, так как была ошибка в транзакции
12. asved.ru 36 07.02.18 14:45 Сейчас в теме
(8) Логично, транзакции для этого и предназначены. Но при корректной обработке исключения ничего исследовать не придется.
11. unichkin 1171 07.02.18 14:36 Сейчас в теме
(7) не, не так. Я говорю что лопатой копать надо, а не пальцы рубить. Неправильное, или лучше сказать - непродуманное использование лопаты может привести к печали.. Вон в ерп успешно ею дрова рубят, т.к. понимают что делают. А если кто-то по незнанию уже себе в ногу целит - я как-бы предостерегаю)
Оставьте свое сообщение