如何在T-SQL中的新事务中写入表

时间:2018-02-16 10:53:49

标签: sql-server tsql transactions commit rollback

我们需要在我们的存储过程中将消息记录到数据库 - 基本上写入表。但是,如果需要回滚事务,我们会丢失这些日志。

有没有办法在新的或不同的事务中编写这些日志(表插入)以确保它们是持久的,而不管当前存储过程的事务是什么?

4 个答案:

答案 0 :(得分:0)

滥用变量(包括表格)免于交易的事实。将日志存储在表var中,在执行常规事务后从中插入。

这应该足以满足您的日志记录需求。

一个明显的缺点是,您无法使用(nolock)实时监控消息,因此请考虑将两者插入 LogTable 表格变量,仅在回滚

上使用 TableVariable

答案 1 :(得分:0)

您希望在此处搜索的关键词是“自治事务”,这是Oracle内置的一项功能,通常希望在SQL Server方案中进行复制。在搜索中使用它,你会发现很多关于如何做的参考。

这是可行的,虽然有点复杂 - 一个选项是创建一个循环的反向链接服务器(链接到你自己)并运行你的日志查询,将其设置为不在分布式事务中运行 - 免除来自事务范围内的日志查询。

MSDN文章详细说明:https://blogs.msdn.microsoft.com/sqlprogrammability/2008/08/22/how-to-create-an-autonomous-transaction-in-sql-server-2008/

答案 2 :(得分:0)

感谢安德鲁 - 这里是您的链接的MS示例的简化版本。

重点是创建链接服务器:

'EXEC sp_addlinkedserver @server = 'linkbackServer,@srvproduct = N' ',@provider = N'SQLNCLI', @datasrc = @@SERVERNAME ' 

有2个选项

不要使用父交易

'EXEC sp_serveroption @serverName,N'remote proc transaction promotion','FALSE' 

允许远程过程调用

'EXEC sp_serveroption @serverName,N'RPC OUT','TRUE' 

这里是创建和测试的所有代码

-- Create the linked server

    use tempdb
    declare @serverName varchar(10) = N'loopback'
    if exists (select * from sys.servers where is_linked = 1 and name = @serverName) begin
       exec sp_dropserver @server=@serverName
    end

    EXEC sp_addlinkedserver @server = @serverName,@srvproduct = N' ',@provider = N'SQLNCLI', @datasrc = @@SERVERNAME 
    EXEC sp_serveroption @serverName,N'remote proc transaction promotion','FALSE' 
    EXEC sp_serveroption @serverName,N'RPC OUT','TRUE' 


    -- Create the logging and testing tables
    if exists (select * from sys.all_objects where name = 'ErrorLogging' and type = N'U') begin
        DROP TABLE ErrorLogging
    END
    CREATE TABLE ErrorLogging (logTime DATETIME, id int, msg VARCHAR(255)) 

    if exists (select * from sys.all_objects where name = 'TestAT' and type = N'U') begin
       DROP TABLE TestAT
    END
    CREATE TABLE TestAT (id INT PRIMARY KEY) 
    GO

    -- create the logger stored proc
    if exists (select * from sys.all_objects where name = 'MyLogger' and type = N'P') begin
      DROP PROCEDURE [dbo].[MyLogger]
    END
    GO

    CREATE PROCEDURE MyLogger 
       @errNumber INT,
       @errMessage varchar(50)
    AS BEGIN
          INSERT INTO ErrorLogging VALUES 
            (GETDATE(), @errNumber, @errMessage ) 
    END
    GO

    -- test the code
    USE tempdb
    delete from dbo.TestAT;
    delete from errorLogging;

    BEGIN TRAN 
      INSERT INTO TestAT VALUES (1) 
      EXEC [loopback].[tempdb].dbo.MyLogger @errNumber = 42, @errMessage = N'this will be saved'
      EXEC [tempdb].dbo.MyLogger @errNumber = 66, @errMessage = N'this will NOT be saved'
    ROLLBACK 

    SELECT * FROM TestAT 
    SELECT * FROM ErrorLogging GO

答案 3 :(得分:0)

根据您的日志记录的强度,如何使用TRY / CATCH进行显式事务处理?我在这里是伪编码,但它得到了重点:

CREATE PROCEDURE dbo.WhatHaveYou
AS
BEGIN
  DECLARE @EnoughVariablesToCaptureErrorMessageSeverityEtc.
  BEGIN TRANSACTION Proc
  BEGIN TRY
    <Body of your proc>
    COMMIT TRANSACTION Proc
  END TRY
  BEGIN CATCH
    SELECT @EnoughVariables... = ERROR_MESSAGE(), ERROR_SEVERITY(), etc.
    ROLLBACK TRANSACTION Proc
    INSERT INTO dbo.LoggingTable VALUES (@EnoughVariables....)
  END CATCH
END

您可以添加更多变量并将它们分配给CATCH块中的日志消息,然后在ROLLBACK之后重新写入它们。