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

Sql server 如何在T-SQL中的新事务中写入表,sql-server,tsql,transactions,commit,rollback,Sql Server,Tsql,Transactions,Commit,Rollback,我们需要将消息记录到存储过程中的数据库中,基本上是写入表中。但是,如果需要回滚事务,我们将丢失这些日志 有没有办法将这些日志表插入写入新的或不同的事务中,以确保它们被持久化,而不管当前存储过程的事务是什么?滥用变量包括表不受事务影响这一事实。将日志存储在表变量中,在执行常规事务后从表变量中插入日志 这应该足以满足您的日志记录需求 一个明显的缺点是,使用NoLoCK无法实时监视消息,因此考虑将两者都插入到日志表和表变量中,并且只使用Relabuty > P>上的Table变量。您要在这里搜索的关键

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


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

滥用变量包括表不受事务影响这一事实。将日志存储在表变量中,在执行常规事务后从表变量中插入日志

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


一个明显的缺点是,使用NoLoCK无法实时监视消息,因此考虑将两者都插入到日志表和表变量中,并且只使用Relabuty

> P>上的Table变量。您要在这里搜索的关键字短语是“自治事务”,它是Oracle中构建的一个特性,通常希望在SQL Server场景中复制的。在你的搜索中使用它,你会找到很多关于如何做的参考资料

这是可行的,尽管有点复杂-一个选项是创建一个到您自己的环回链接服务器链接,并针对该链接运行日志查询,将其设置为不在分布式事务中运行-这使得日志查询不在事务范围内


MSDN文章及其详细说明:

谢谢Andrew-这里是MS示例的简化版本,您的链接

要点是创建链接服务器:

'EXEC sp_addlinkedserver @server = 'linkbackServer,@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 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

根据日志记录的强度,使用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块中的日志消息中,然后在回滚后重新写入它们(如果愿意)。

另请参阅我不得不问的可能的副本-为什么这是一个如此次要的主题?没有很多人需要记录消息,不管是错误消息还是调试消息,或者介于两者之间的任何消息。登录数据库似乎是一种可靠的设计模式。@JohnLedger,我同意你的看法。从C代码来看,像这样的基本日志记录在SQL Server中并不容易,这似乎很奇怪。是的,可以做到这一点,在大多数情况下,这是一个改进的解决方案。我们在调用代码Java中处理事务,所以在我们的例子中,我们不能t@JohnLedger,我所知道的Java就是,如果没有放在我桌上的杯子,我就无法运行。祝你好运