在我的.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,这意味着在提交数据库事务之前,消息不会发布到队列中。
我的要求:在存储过程外部启动的隐式事务中,某些第三方应用程序正在触发我们的应用程序存储过程。我希望能够在我的存储过程中捕获并记录任何错误(在同一数据库中的数据库表中)。我需要重新抛出异常,让第三方应用程序回滚事务,并让它知道操作失败(因此在发生故障时执行任何操作)。
答案 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;