В этой статье я постарался систематизировать статьи ИТС и собственный опыт в плане обхода опасностей, сопровождающих использование транзакций в 1С. Транзакционные блокировки в статье не рассматриваются. К статье приложена демо база. При ее запуске откроется обычное приложение и форма с кнопками для выполнения примеров, на которые ссылается статья серым шрифтом.
Транзакции применяются для целостного изменения связанных данных, т. е. все действия с базой данных, выполняемые в рамках транзакции или выполняются целиком, или целиком откатываются.
Таблица операций, воздействующих на менеджер транзакции
Выброс исключения
Признак отмены транзакции
Фактическая транзакция (СУБД)
Начало записи объекта (неявное начало транзакции)
+1 при программной записи;
Не меняется при интерактивной записи
Конец записи объекта (неявный конец транзакции)
-1 при программной записи;
Не меняется при интерактивной записи
Если глубина стала 0
Если глубина стала 0
Операция (явная или неявная) с БД в транзакции
Исключение в транзакции
Ошибки в транзакции могут быть
Проверка сломанной транзакции
При необходимости устранить ложные срабатывания, можно будет еще анализировать описание ошибки. Кстати обращения к серверу СУБД этот запрос не производит (только к модели БД).
Подготовка данных для обработки исключения в сломанной транзакции
В ряде случаев имеет смысл готовить данные для обработки исключения заранее, т. е. до выполнения опасной операции с БД, которая может сломать транзакцию. Особенно актуально это для предотвращения обращений к объектному кэшу и кэшу представлений, которые могут вызывать невосстановимые ошибки в сломанной транзакции в случае необходимости считывания данных в этот кэш. Также в рамках этой подготовки можно наполнить объектный кэш и кэш представлений ссылок нужными ссылками, но делать это нужно в транзакции. Тут важно найти оптимальный баланс между дополнительными подготовительными обращениями к БД и диагностической ценностью этих данных для обработки потенциальных исключений. В случае риска обращений к кэшу представлений для регистрации диагностической информации вместо подготовки данных можно в качестве альтернативы использовать идентификаторы ссылок.
Передача ссылки в журнал регистрации в сломанной транзакции
При обработке исключения в сломанной транзакции часто разумно писать диагностическую информацию в журнал регистрации. При этом метод ЗаписьЖурналаРегистрации() неявно берет представление от ссылки, используя кэш представлений ссылок, и помещает его в поле "Представление данных" события журнала. Обращение к этому кэшу в сломанной транзакции несет риск невосстановимой ошибки. Поэтому рекомендую передавать ссылку в журнал регистрации только через эту функцию (общий модуль ОбщийМодуль1)
Тогда безопасная запись в журнал регистрации при обработке исключения в транзакции может выглядеть так
Открывать и закрывать транзакцию в одном методе
Операции с БД в сломанной транзакции
Иногда бывает нужно в сломанной транзакции (например при обработке исключения) выполнить очень важную операцию с БД.
В таком случае может быть оправдано пренебречь рекомендацией "Открывать и закрывать транзакцию в одном методе" и завершить фактическую транзакцию в текущем месте, чтобы сделать возможным выполнение этой важной операции с БД.
Также для выполнения очень важной операции с БД в сломанной транзакции можно использовать запуск фонового задания.
Рекомендуемая структура кода транзакции
Пример (кнопка " Обработка ошибки в явной транзакции" )
Шаблон транзакции
Создайте себе шаблон текста транзакции (команда "Сервис"/"Шаблоны текста" конфигуратора)
Скрытая отмена транзакции
Этот пример демонстрирует, что даже без вызова ОтменитьТранзакцию() явная фактическая транзакция может быть отменена. При завершении при установленном признаке Отменена явная транзакция молча откатывается в отличие от неявной транзакции, которая выбрасывает исключение "В данной транзакции уже происходили ошибки". Не рекомендую применять это, однако рекомендую изучить для лучшего понимая всех тонкостей работы транзакций (к нопка "Скрытая отмена транзакции")
В ряде случаев может быть полезным выбрасывать исключение в такой ситуации по аналогии с неявной транзакцией. Для этого вместо вызова штатного метода предлагаю использовать собственный метод ЗафиксироватьТранзакциюОбязательно()
Другим примером скрытой отмены транзакции является завершение потока встроенного языка, которое происходит при
Разрыв неявной транзакции
Этот пример демонстрирует довольно неочевидную возможность разорвать фактическую транзакцию программной записи объекта. Не рекомендую применять это, однако рекомендую изучить для лучшего понимая всех тонкостей работы транзакций (к нопка "Разрыв записи объекта", справочник РазрывЗаписиОбъекта модуль Объекта)
Если же попробовать сделать тот же фокус с интерактивной записью объекта, то на вызове ЗафиксироватьТранзакцию() будет выброшено исключение "Транзакция не активна".
Поиск установки признака отмены транзакции
Как было показано выше, установленный признак отмены транзакции может приводить к различным трудно диагностируемым классическими средствами ошибкам дальше по трассе кода. Поэтому важно иметь способ быстро находить место в коде, где установился этот признак.
Тут нам поможет техножурнал. Достаточно включить на сервере приложений сбор события SDBL с отбором Func=’setRollbackOnly’. В инструменте "Настройка техножурнала (ИР)" из подсистемы Инструменты разработчика регистрация этого события входит в шаблон "Дежурный"
Пример регистрации такого события при выполнении кода на толстом клиенте:
При выполнении кода на сервере на платформе 8.3.18 при вызове метода ОтменитьТранзакцию() мне не удалось добиться регистрации такого события. Постараюсь позже дополнить причиной. Пример регистрации такого события при выполнении кода на сервере:
Полезные статьи по теме
Скачать файлы
Специальные предложения
Также как я уже отметил в статье, есть еще неявные транзакции, которые в общем случае невозможно отличить от явных. Если такой прием применить внутри внешней неявной транзакции, то мы ее отменим. А платформа, когда дойдет до обработки ее завершения, как показано в таблице из статьи выбросит невосстановимое исключение (в демо базе кнопка «Невосстановимая ошибка после отмены транзакции в неявной транзакции»). Ведь платформа не проверяет активность транзакции при завершении неявной транзакции.
Почему метод НачатьТранзакцию нельзя писать в блоке Попытка-Исключение непосредственно после оператора Попытка?
Как избежать взвода признака “Отмены” менеджера транзакций при обработке исключения внутри транзакции? (при записи подчинённого объекта/обращении к веб-сервису/вызове экспортных процедур записи в бд из других модулей)
(10) Это общий стандарт, не только для 1С. В попытке или обработчике исключения должны выполняться действия уже после начала транзакции.
Маловероятно, но что, если исключение будет вызвано непосредственно вызовом НачатьТранзакцию()?
В этом случае мы попадём в обработчик исключения где тут же начнем откатывать транзакцию и получим ещё одну ошибку.
А перед отменой транзакции в обработчике исключения некорректно ставить условие «Если ТранзакцияАктивна()». Об этом уже написали выше, ведь в этом случае мы можем зацепить алгоритмы, находящиеся по стеку выше исполняемого кода и вообще нарушаем модульность программы.
Поэтому действительно целесообразно сначала открывать транзакцию и только потом открывать блок Попытка-Исключение. А в обработчике исключения сразу отменять её без всяких проверок и циклов.
Согласен с тем, что в общем случае это ошибка. Но в том, что это распространено в типовых конфигурациях, есть сомнения. Это встречается редко. Например когда метод закрывает транзакцию, открытую в другом методе, и это является скорее исключением в типовых конфигурациях, а не правилом.
Например взял конфигурацию ERP и провел поиск регуляркой. Скриншот прикладываю. Случаев такого «злоупотребления» очень мало и они в встречаются в основном в служебных модулях. Есть всего пара случаев где разработчики такого могли бы избежать: модули СообщенияОбменаДаннымиУправлениеОбработчикСообщения_2_1_2_1 и ОбменСообщениямиВнутренний.
(0) Я использую следующий шаблон (на основе статьи с хабра EvilBeaver)
(25) Тут идея в том, что код может выполняться во «враждебной среде» и потому, данный сниппет является довольно универсальным:
Https://habr. com/ru/post/419715/
Подсмотрел у Овсянкина, за что большое ему спасибо :3
(33) Да, между получением представления объекта и записью в ЖР может пройти, увы, более 20 секунд.
Особенно это актуально из-за времени ожидания блокировки данных, которое как раз тоже равно 20 секундам (по умолчанию).
Недавно словил как раз такую ошибку.
Демобаза из Вашего примера.
По причине:
Транзакция не активна
На 8.2.19.130 аналогично
Скрины:
1) работает программная запись
2) попытка создания нового элемента
3) не работает интерактивная
Или речь про отличие поведения системы в файлом варианте и клиент-серверном?
(47)На запись/удаление объектов в/из БД / на явную и не явную отмену транзакций.
Из вашего описания складывается впечатление, что в коде присутствует ОтменитьТранзакцию() без НачатьТранзакцию()
Если ошибок выполнения не возникает, то остановка по ошибке не выполнится.
1. Автор оперирует выражением «Вложенные транзакции», цитата с ИТС:
Про «вложенные логические» транзакции слышу впервые и даже гугл мне не помог понять, что это такое, автор что-то изобрел?
2. Нет никакой глубины транзакции в 1С, есть внутренний счетчик транзакций.
Исключение в транзакции
Ошибки в транзакции могут быть
Если произошедшая ошибка не связана с базой данных, то возможно продолжение транзакции и дальнейшей работы модуля. Если разработчик считает это необходимым, он может отменить транзакцию или, наоборот, продолжить выполнение транзакции, если произошедшая ошибка не нарушает атомарность транзакции.
Если же исключительная ситуация была вызвана ошибкой базы данных, то система фиксирует факт возникновения ошибки в этой транзакции, и дальнейшее продолжение транзакции или ее фиксация становятся невозможны. Единственная операция с базой данных, которую разработчик может произвести в данной ситуации, – это отмена транзакции. После этого он может осуществить попытку выполнения этой транзакции еще раз.
Автор предлагает в качестве шаблона использовать код:
Шаблон станет выглядеть так:
В данной транзакции уже происходили ошибки 1С 8.3 как исправить?
Программа 1С является самой популярной и наиболее удобной при автоматизации предприятия. В ней предусмотрены решения, созданные на базе одной платформы, соответственно, функционируют они по одному принципу, что значительно упрощает использование ПО. Нередко пользователи сталкиваются с сообщением «В данной транзакции уже происходили ошибки». Рассмотрим как в 1С 8.3 исправить подобную проблему.
Причина появления сообщения о повторных ошибках в 1С 8.3
Главная проблема заключается в том, что сообщение об ошибке «В данной транзакции уже происходили ошибки» неинформативно, нет никакой конкретики. Поэтому будем опираться на проблемы, с которыми чаще всего сталкиваются пользователи. Например, с технической стороны ошибка такого рода может возникнуть при первой транзакции, то есть и при первичном обращении к базе данных.
Подобная ошибка может произойти при обработки ситуации «Попытка-Исключение». Например, при создании записи «Объект_1» формируется исключительная ситуация, а сама ошибка появляется в «Ссылка_2.Наименование». То есть происходит запрос базы данных объектной модели.
В «Попытке-Исключение» начинается обработка операции, которая также должна быть выполнена в транзакции, которая, в свою очередь, может быть явной или неявной (создается в момент записи объекта).
1С: Предприятие 8.3 не поддерживает транзакций вложенного типа. Однако допускается создание вложенной конструкции сразу нескольких транзакций. Из-за наличия явной и неявной транзакции может возникнуть ошибка. То-есть программа запрещает транзакцию 1-го уровня на более низших уровнях.
Есть ли смысл исправлять ошибки транзакции, которые уже происходили
При работе с 1С 8.3 не стоит оставлять подобные вещи без внимания. Прежде всего, другой пользователь также может столкнуться с ней, но не поймет причин её возникновения. Если не выполнить отладку системы, то в дальнейшем могут возникнуть дополнительные проблемы. Так как оповещение «В данной транзакции уже происходили ошибки» появляется при первом обращении, то в журнале регистрации данная строка обязательно зафиксируется, но, опять же, без подробного пояснения. Хоть ошибка и располагается на нижнем уровне кода, она нарушит необходимую иерархию. Это приведет к сбою других функций и только еще больше запутает администратора.
При наличие некорректного кода, транзакции будут выполняться с нарушениями или не будут выполняться вовсе. Поэтому при возникновении таких сообщений стоит решить проблему.
Устраняем ошибку транзакции в 1С Предприятие версии 8.3
В первую очередь стоит очистить кэш базы данных. Сделать это можно вручную. Для этого:
Также можно выполнить удаление другим способом:
После того, как файл преобразуется, его можно запустить и весь пользовательский кэш удалится автоматически. Пробуем снова запустить программу и выполнить операцию. Если не помогло, то лучше всего обратиться к администратору. Также нужно помнить про основные особенности написания кода с использованием транзакций. Это поможет исключить ряд распространенных ошибок.
Особенности написания кода, которые помогут исключить ошибку в транзакциях
Прежде всего нужно опираться на нюансы корректной обработки исключений:
Решить проблему транзакций, в которых происходят ошибки, самостоятельно получается не всегда. Поэтому стоит попробовать выполнить простейшие действия – перезагрузить программу или очистить кэш. К более серьезным манипуляциям в 1С стоит переходить только при уверенности, что вы обладаете достаточным опытом.
Https://infostart. ru/1c/articles/1026771/
Https://rusadmin. biz/soveti/v-dannoj-tranzaktsii-uzhe-proishodili-oshibki-1s-8-3/