SQL Server / T-SQL: Raiserror отменяет предыдущие вставки - PullRequest
0 голосов
/ 01 октября 2019

В процедуре я хочу сделать тест, затем Raiserror, когда это действительно так. Но перед этим я хочу записать ошибку в таблицу. Мой код такой:

CREATE PROCEDURE proc
    @val VARCHAR(50)
AS 
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT OFF;

    DECLARE @test VARCHAR(50)

    SELECT @test = test  
    FROM test_table 
    WHERE ...

    IF @test IS NULL
    BEGIN
        INSERT INTO log_table VALUES (@val);
        RAISERROR ('Invalid value : %i', 16, 1, @val);  
    END
END

Код компилируется. При выполнении с неверным значением возникает ошибка, но вставка отменяется.

Я пытался включать и выключать xact_abort и nocount, но безуспешно.

Я пыталсяинкапсулируя запрос вставки в BEGIN TRANSACTION/COMMIT, но все равно получая тот же результат.

Что я заметил, мой log_table, который имеет идентификатор автоинкремента, увеличивается, даже когда эти вставки отменяются.

Как я могу вызвать ошибку, но сохранить запрос на вставку?

Спасибо

Ответы [ 3 ]

2 голосов
/ 01 октября 2019

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

Так что-то вроде:

CREATE Procedure myproc 
    @val varchar(50)
as
begin
    set nocount on
    set xact_abort on

    begin transaction;
    begin try
       -- do stuff

       commit transaction;
    end try
    begin catch
      if @@trancount > 0 rollback;

      declare @error_message varchar(max) = error_message()
      INSERT INTO log_table values (@val);

      throw;
    end catch
end
2 голосов
/ 01 октября 2019

Попробуйте использовать THROW вместо:

CREATE TABLE dbo.log_table (val varchar(50));

GO
CREATE PROCEDURE dbo.[proc] @val varchar(50)
AS
BEGIN


    SET NOCOUNT ON;
    SET XACT_ABORT OFF;


    DECLARE @test varchar(50); --As i never set this, it'll go into the IF

    IF (@test IS NULL)
    BEGIN
        INSERT INTO log_table
        VALUES (@val);
        THROW 51000, N'Invalid value.', 1;

    END;

END;
GO
EXEC dbo.[proc] @val = 'Some Value';

GO

SELECT *
FROM dbo.log_table;
GO


DROP PROC dbo.[proc];
DROP TABLE dbo.log_table;

DB <> Fiddle

0 голосов
/ 02 октября 2019

Так что, очевидно, моя процедура работала, как и ожидалось, на стороне SQLServer. Проблема заключалась в том, что я вызывал эту процедуру из собственного метода запросов Java / Spring, и его нужно было аннотировать с помощью @Modifying и @Transactional, поскольку он выполняет вставки. Таким образом, когда исключение было обнаружено, оно автоматически откатывалось.

Я не нашел быстрого решения для обхода транзакции Spring. Теперь я думаю, что все, что мне нужно сделать, это перехватить исключение на уровне приложения и войти в log_table на уровне приложения тоже

...