2017-08-17 199 views
2

我需要从存储过程写入日志表。 现在这个日志信息必须在回滚场外生存。在当前事务之外提交事务(如Oracle中的自治事务)

我知道这个问题已被问过,但我的情况是不同的,我无法在这些问题中找到我的问题的答案。

当存储过程中没有错误时,事情很简单,日志表中的条目就在那里。
出现错误时比事情复杂。
在过程中,我可以在catch中回滚,然后将数据插入到日志表中,我知道这一点,而且我已经这样做了。
但问题是,当调用存储过程是这样的:

begin transaction 
exec myStoredProcedure 
rollback transaction 
select * from myLogTable 

我知道这个代码使没有太大意义,我一直是mimimal来证明我的问题。
如果存储过程的调用者执行了提交/回滚,那么它对我在存储过程中所做的并不重要。我的logentry将永远回滚。

我也不能使用临时表技巧,它是返回我想要记录的数据,并让调用者使用该数据在完成回滚之后将其插入到日志表中,因为调用者是外部应用程序我没有来源。

日志记录是在一个单独的过程中完成的,只有一行代码插入到日志表中。
我需要的是一种在当前事务之外的过程中提交插入的方式,因此它可以在任何回滚之后存活。

有没有办法做到这一点?

解决方案:

我用lad2025答案,迄今为止,它是工作没有任何问题或性能问题。
但是这个过程每天只会被调用大约1000次,这并不是那么多,所以我想我也不需要任何问题。

回答

2

这是很有趣的话题让我们检查MS如何处理它。

第一文档:Migrating-Oracle-to-SQL-Server-2014-and-Azure-SQL-DB.pdf

页152

模拟甲骨文自治事务

本节介绍SSMA为Oracle V6.0如何处理自治事务 (PRAGMA AUTONOMOUS_TRANSACTION)。这些自治事务不在 中具有Microsoft SQL Server 2014中的直接等效项。

当您将自定义PL/SQL块您将 与该调用程序的事务上下文中的DML隔离开来。该块变为 由另一个交易开始的独立交易,被称为主要交易 。

了标记PL/SQL块作为一个自治事务,您只需包括 按照你的声明部分声明: PRAGMA AUTONOMOUS_TRANSACTION;

SQL Server 2014不支持自治事务。将Transact-SQL块与事务上下文分离的唯一方法是打开一个新的连接。

使用xp_ora2ms_exec2扩展过程和它的扩展版本 xp_ora2ms_exec2_ex,与SSMA 6.0扩展包捆绑在一起,开辟新的 交易。该过程的目的是调用新连接中的任何存储过程,并帮助调用函数体内的存储过程。该 xp_ora2ms_exec2程序的语法如下:

xp_ora2ms_exec2 
<active_spid> int, 
<login_time> datetime, 
<ms_db_name> varchar, 
<ms_schema_name> varchar, 
<ms_procedure_name> varchar, 
<bind_to_transaction_flag> varchar, 
[optional_parameters_for_procedure]; 

然后,你需要安装在你的服务器的存储过程和其他脚本: SSMA for Oracle Extension Pack(仅SSMA用于Oracle扩展Pack.7.5.0.msi)。

你的存储过程将变成:

CREATE TABLE myLogTable(i INT IDENTITY(1,1), 
         d DATETIME DEFAULT GETDATE(), 
         t NVARCHAR(1000)); 
GO 

CREATE OR ALTER PROCEDURE my_logging 
    @t NVARCHAR(MAX) 
AS 
BEGIN 
    INSERT INTO myLogTable(t) VALUES (@t); 
END; 
GO 

CREATE OR ALTER PROCEDURE myStoredProcedure 
AS 
BEGIN 
    -- some work 
    SELECT 1; 
    INSERT INTO myLogTable(t) 
    VALUES ('Standard logging that will perish after rollback'); 

    DECLARE @login_time DATETIME = GETDATE(); 
    DECLARE @custom_text_to_log NVARCHAR(100); 
    SET @custom_text_to_log=N'some custom loging that should survive rollback'; 
    DECLARE @database_name SYSNAME = DB_NAME(); 

    EXEC master.dbo.xp_ora2ms_exec2_ex 
     @@spid, 
     @login_time, 
     @database_name, 
     'dbo', 
     'my_logging', 
     'N', 
     @custom_text_to_log; 
END; 

和最终呼叫:

begin transaction 
exec myStoredProcedure 
rollback transaction 
select * from myLogTable; 

OUTPUT:

i d   t 
2 2017-08-21 some custom loging that should survive rollback 
+0

这看起来很有趣。可以安装扩展包而不使DB脱机?它会影响性能吗?后者是很重要的,因为日志记录是很容易发生的事情 – GuidoG

+0

@GuidoG安装非常简单,它执行一组脚本(最终将在主DB中包含许多存储过程/类型)。我不测试性能(我会建议在DEV/QA env上尝试它)并进行大量测试。 – lad2025

+0

好的我会这么做,谢谢 – GuidoG

2

所以你真的搜索某种Autonomous transaction(就像在Oracle中)。

模拟它的一个难看的方法是使用环回链接服务器。

警告:这是PoC(在我将它用于PROD之前我会考虑两次)并进行大量测试。

DECLARE @servername SYSNAME; 
SET  @servername = CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName')); 

EXECUTE sys.sp_addlinkedserver 
      @server = N'loopback', 
      @srvproduct = N'', 
      @provider = N'SQLNCLI', 
      @datasrc = @servername; 

EXECUTE sys.sp_serveroption 
      @server = N'loopback', 
      @optname = 'RPC OUT', 
      @optvalue = 'ON'; 

EXECUTE sys.sp_serveroption 
     @server = N'loopback', 
     @optname = 'remote proc transaction promotion', 
     @optvalue = 'OFF'; 

和代码:

DROP TABLE IF EXISTS myLogTable; 
CREATE TABLE myLogTable(i INT IDENTITY(1,1), 
         d DATETIME DEFAULT GETDATE(), 
         t NVARCHAR(1000)); 
GO 

CREATE OR ALTER PROCEDURE my_logging 
    @t NVARCHAR(MAX) 
AS 
BEGIN 
    INSERT INTO myLogTable(t) VALUES (@t); 
END; 
GO 

CREATE OR ALTER PROCEDURE myStoredProcedure 
AS 
BEGIN 
    -- some work 
    SELECT 1; 
    INSERT INTO myLogTable(t) 
    VALUES ('Standard logging that will perish after rollback'); 

    EXEC loopback.T1.dbo.my_logging 
     @t = N'some custom loging that should survive rollback'; 
END; 

最终调用:

begin transaction 
exec myStoredProcedure 
rollback transaction 
select * from myLogTable 

输出:

i d   t 
2 2017-08-17 some custom loging that should survive rollback 
+0

是自治事务就是我所期待的。我已经找到一篇关于环回链接服务器的文章,但他们也警告说要使用它,因为频繁使用时会出现性能问题。 – GuidoG