.NET TransactionScopeOption.Suppress

时间:2016-04-26 07:28:05

标签: c# sql-server tsql transactions transactionscope

在我的.NET代码中,在数据库事务中(使用TransactionScope),我可以包含一个带有TransactionScopeOption.Suppress的嵌套块,这可以确保嵌套块中的命令即使在外部也可以提交挡回来。 以下是代码示例:

using (TransactionScope txnScope = new TransactionScope(TransactionScopeOption.Required))
{
    db.ExecuteNonQuery(CommandType.Text, "Insert Into Business(Value) Values('Some Value')");

    using (TransactionScope txnLogging = new TransactionScope(TransactionScopeOption.Suppress))
    {
        db.ExecuteNonQuery(CommandType.Text, "Insert Into Logging(LogMsg) Values('Log Message')");
        txnLogging.Complete();
    }

    // Something goes wrong here. Logging is still committed

    txnScope.Complete();
}

我试图找到是否可以在T-SQL中完成。有些人推荐OPENROWSET,但它看起来并不优雅。使用。此外,我认为将连接信息放在T-SQL代码中是一个坏主意。

我以前使用过SQL Service Broker,但它也支持Transactional Messaging,这意味着在提交数据库事务之前,消息不会发布到队列中。

我的要求:在存储过程外部启动的隐式事务中,某些第三方应用程序正在触发我们的应用程序存储过程。我希望能够在我的存储过程中捕获并记录任何错误(在同一数据库中的数据库表中)。我需要重新抛出异常,让第三方应用程序回滚事务,并让它知道操作失败(因此在发生故障时执行任何操作)。

2 个答案:

答案 0 :(得分:4)

您可以设置一个环回链接服务器,并将remote proc transaction Promotion选项设置为false,然后在TSQL中访问它,或者使用SQL Server中的CLR过程在事务外部创建新连接并完成工作。< / p>

How to create an autonomous transaction in SQL Server 2008中建议使用这两种方法。

这两种方法都涉及创建新连接。有一个open connect item请求本机提供此功能。

答案 1 :(得分:0)

表变量中的值存在于ROLLBACK之外。

因此,在下面的示例中,由于OUTPUT和表变量的组合,所有要删除的行都可以插入到持久化表中并稍后查询。

-- First, create our table
CREATE TABLE [dbo].[DateTest] ([Date_Test_Id] INT IDENTITY(1, 1), [Test_Date] datetime2(3));

-- Populate it with 15,000,000 rows
-- from 1st Jan 1900 to 1st Jan 2017.
INSERT INTO [dbo].[DateTest] ([Test_Date])
SELECT 
TOP (15000000)
    DATEADD(DAY, 0, ABS(CHECKSUM(NEWID())) % 42734)
    FROM [sys].[messages] AS [m1]
    CROSS JOIN [sys].[messages] AS [m2];

BEGIN TRAN;

BEGIN TRY

    DECLARE @logger TABLE ([Date_Test_Id] INT, [Test_Date] DATETIME);

    -- Delete every 1000 row
    DELETE FROM [dbo].[DateTest]
    OUTPUT deleted.Date_Test_Id, deleted.Test_Date INTO @logger
    WHERE [Date_Test_Id] % 1000 = 0;

    -- Make it fail
    SELECT 1/0

    -- So this will never happen
    COMMIT TRANSACTION;

END TRY
BEGIN CATCH

    ROLLBACK TRAN
    SELECT * INTO dbo.logger FROM @logger;

END CATCH;

SELECT * FROM dbo.logger;

DROP TABLE dbo.logger;