Делаем вставку без отката - PullRequest
       24

Делаем вставку без отката

0 голосов
/ 26 сентября 2018

Вот странный вопрос: есть ли способ сделать вставку без отката в таблицу?

Вот сценарий: у нас есть триггер, который что-то делает.

Иногда этот триггерпозвонит RAISERRROR().И внешняя транзакция откатывается назад.

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

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Если вы создадите табличную переменную, а затем вставите ее в нее - она ​​не будет включена в откат, поэтому вы можете затем вывести содержимое в постоянную таблицу.

Например,

declare @tab table (msg varchar(255))

BEGIN TRY

    BEGIN TRANSACTION

    select 1+2

    INSERT @tab values ('first step complete')

    SElect 1/0

    INSERT @tab values ('2nd step complete')

    COMMIT

END TRY

BEGIN CATCH

    ROLLBACK

    SELECT * FROM @tab
END CATCH
0 голосов
/ 26 сентября 2018

Банановый улов

Вы можете ловить исключения с помощью try-catch и передавать / выбрасывать их во внешнюю область видимости, где должны существовать такие же вещи.Это, кстати, позволяет собирать call-stack.Это решение может быть реализовано, если вы работаете только через сохраненные программы.Каждый процесс должен иметь такой шаблон:

begin try
end try
begin catch
   if @@trancount > 0
     rollback

   insert into <log> (...)
   values (...)

   throw
end catch

Таким образом, самая верхняя процедура успешно вставит строку в таблицу журнала.

Минусы:

  • с глубокимиерархия - слишком много «фиктивных» вставок для отката
  • все еще возможно ничего не регистрировать, если:
    • серьезность слишком высока
    • SP не соответствует этому шаблону
    • есть внешнее / "клиентское" управление транзакциями

Плюсы:

  • Не идеально, но выполнимо и не слишкомтрудно реализовать.

Обратная связь:

  • Я использовал этот подход на производственном сервере небольшого проекта, собирал стек вызовов и так далее.Это было бэк-офисное программное обеспечение с ~ 50-100 онлайн-пользователями, с некоторым количеством работающих роботов, далеко не "высоконагруженным".Работало нормально, помогло исправить многие проблемы.Накладные расходы никого не беспокоили.

неуловимый бандит

Вы можете создать CLR-сборку, которая вставляется в таблицу журнала и ничего более ... Но!Можно указать отдельное соединение, чтобы эта сборка работала с БД через это отдельное соединение.Что означает - в отдельной области.Таким образом, метод этой сборки вызывается из транзакции, однако выполняется независимо от области транзакции.

Таким образом, вместо:

using(SqlConnection connection = new SqlConnection("context connection=true"))

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

begin try
end try
begin catch
   if @@trancount > 0
     rollback

   if @@ERRROR_STATUS != @done_with_logging
     exec asm.log(...)

   raiserror @err_msg, @severity, @done_with_logging
end catch

Минусы:

  • может привести к проблемам в пуле соединений
  • немного более длинный способ получить тривиальную вставку
  • может вызвать дополнительные проблемы, связанные с установлением соединения и самой сборки (+ разрешения, владение и т. д.)

Плюсы:

  • идея немного волнующая
  • может войти в файл вместо db

Обратная связь:

  • Я не могупомните, использовал ли я этот подход на prod (хотя я вспоминаю это как более недавний опыт ... или просто как попытку реализовать это в целях тестирования)

knock, knock, admin

Этот простой оператор (на самом деле это просто дополнительная опция WITH LOG) запишет любое сообщение об ошибке, которое вы хотите, в журнал событий SQL SERVER:

RAISERROR(...) WITH LOG

Это не тот способ, которым SQL SERVERЖурнал должен быть использован, но это самый быстрый способзаписать что-то важное (для разрешения проблемы).Записанное событие можно просмотреть в окнах агента SSMS.

Минусы:

  • могут быть соображения относительно разрешений
  • плохой поиск и нулевые возможности настройки
  • dba возненавидит вас (если он, конечно, будет проверять журналы сервера)

Плюсы:

  • однострочная реализация

Обратная связь:

  • Я сталкивался с таким способом регистрации только в одной компании.Я предполагаю, что некоторое время назад он использовался несколькими разработчиками для выявления незначительных ошибок, но позже получил распространение по всему коду и стал «стандартом».Итак, через некоторое время стало почти невозможно найти что-то конкретное в журнале событий ... и фактически лишь немногие коллеги имели доступ к журналу сервера Prod.Так что буквально а) вредно б) бесполезно.Так что я избавился от этого из управляемой части системы, как только нашел время для.

летающего голландца

{места для основанных на мнении разговоров о построении системы на основеТриггеры DML}

Мне кажется, что вы не используете хранимые процедуры в своем проекте и вместо этого выполняете специальные запросы.Если у вас есть бэкэнд-приложение с ORM или чем-то в этом роде - напишите в него лог.Более того, возможно, это бэкэнд-приложение - лучшее место, чтобы делать то, что вы делаете внутри этого триггера.

Если ваш проект представляет собой клиент-серверное приложение без приложения appserver / backend, и все, что у вас есть, - это специальный запрос итриггер, то не так много данных для входа.Нет стека вызовов (на стороне сервера).И будет трудно определить, как вы (пользователь, приложение) пришли к этому конкретному исключению.Таким образом, регистрация на стороне клиента может быть более полезной в этом случае.

...