【问题标题】:SQL Server / T-SQL : Raiserror cancels prior insertsSQL Server / T-SQL:Raiserror 取消先前的插入
【发布时间】:2019-10-01 14:02:31
【问题描述】:

在一个程序中,我想在实际情况下进行测试然后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_abortnocount,但没有成功。

我尝试将插入请求封装在BEGIN TRANSACTION/COMMIT 中,但仍然得到相同的结果。

我注意到,我的 log_table 具有自动递增 ID,即使在取消这些插入时也会递增。

如何引发错误但仍保留插入请求?

谢谢

【问题讨论】:

  • 无复制。该值出现在表中。您是否有启动和回滚事务的客户端代码?
  • 你是对的。检查我的答案

标签: sql-server tsql sql-server-2012


【解决方案1】:

考虑改用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

【讨论】:

  • 你是对的,@GSerg (DB<>fiddle)。我曾愚蠢地假设 OP 提供了复制“问题”的代码。傻我。 ??‍♂️
  • 您的代码和我的代码都在 sqlserver 端工作。问题出在应用层回滚。检查我的答案
【解决方案2】:

为了写入日志表,您必须回滚任何待处理的事务。否则你的日志表 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

【讨论】:

    【解决方案3】:

    显然,我的程序在 SQLServer 端按预期工作。问题是我从 Java/Spring 本机查询方法调用此过程,并且必须使用 @Modifying 和 @Transactional 进行注释,因为它正在执行插入操作。因此,当捕获到异常时,它会自动回滚。

    我没有找到绕过 Spring 事务的快速解决方案。现在我想我所要做的就是,在 App 层捕获异常并记录到应用层的 log_table 中

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多