我正在使用 C# 和 ADO.NetTransactionScope
在 ASP.Net 应用程序中运行事务。该事务应该在多个表中保存一些数据,然后向订阅者发送电子邮件。
Question: 是否有效使用TransactionScope
,当它包含对在 SQL Server 2014 中拥有自己的事务的存储过程的调用时,或者我应该删除 SQL 事务语句,即begin tran
, commit tran
and rollback tran
在此调用的存储过程中的语句TransactionScope
?
下面提到了该场景的C#代码以及存储过程的T-SQL代码。
C# 代码使用TransactionScope
:
try
{
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection connection1 = new SqlConnection(connectString1))
{
// Opening the connection automatically enlists it in the
// TransactionScope as a lightweight transaction.
connection1.Open();
// SaveEmailData is a stored procedure that has a transaction within it
SqlCommand command1 = new SqlCommand("SaveEmailData", connection1);
command1.CommandType = CommandType.StoredProcedure;
command1.ExecuteNonQuery();
}
//Send Email using the helper method
EmailHelper.SendCustomerEmails(customerIds);
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
}
catch( Exception ex)
{
Logger.Log(ex);
}
存储过程的T-SQLSaveEmailData
:
SET NOCOUNT ON
BEGIN TRY
DECLARE @emailToUserId BIGINT
BEGIN TRAN
-- //update statement. detail statement omitted
UPDATE TABLE1...
--update statement. detail statement omitted
UPDATE TABLE2...
IF @@trancount > 0
BEGIN
COMMIT TRAN
END
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN
ROLLBACK TRAN
END
EXEC Error_RaiseToADONET
END CATCH
Yes, TransactionScope
包装 SQL 时仍然可以工作BEGIN / COMMIT TRANSACTION
或 ADOSqlConnection.BeginTransaction
。包装单个连接时,行为类似于将事务嵌套在Sql
:
However:
-
ROLLBACK TRAN
将中止整个交易(即),除非您正在使用保存积分 https://technet.microsoft.com/en-us/library/ms178157(v=sql.105).aspx (i.e. SAVE TRANSACTION xx
... ROLLBACK TRANSACTION xx
.
- 使用存储过程时,如果连接不正确,您将收到错误
@@TRANCOUNT
退出 SPROC 时的值与进入 SPROC 时的值不同。
因此,通常更容易将事务语义留给TransactionScope
并删除任何手册BEGIN TRAN / COMMIT TRAN
逻辑不会让你的 TSQL 变得混乱。
Edit- 澄清以下评论
在OP的情况下,SPROC在编写时并没有考虑到嵌套事务(即是否由Sql或.Net外部事务包装),具体来说,ROLLBACK
in the BEGIN CATCH
块将中止整个外部事务,并可能导致外部发生进一步的错误TransactionScope
as the @@TRANCOUNT
规则未被遵守。 A像这样的嵌套事务模式 http://rusanu.com/2009/06/11/exception-handling-and-nested-transactions/如果 SPROC 需要以嵌套或独立事务方式操作,则应注意。
SavePoints 不适用于分布式事务 http://www.sommarskog.se/wishlist.html#savepointdistr, and TransactionScope
可以轻松地升级为分布式事务 https://stackoverflow.com/a/22512547/314291例如如果您在事务范围内使用不同的连接字符串或控制其他资源。
因此,我建议将 PROC 重构为“快乐”的核心/内部情况,从事务范围调用此内部过程,并在那里进行任何异常处理和回滚。如果您还需要从 Ad Hoc Sql 调用 proc,则提供一个具有异常处理功能的外部包装器 Proc:
-- Just the happy case. This is called from .Net TransactionScope
CREATE PROC dbo.InnerNonTransactional
AS
BEGIN
UPDATE TABLE1...
UPDATE TABLE2 ....
END;
-- Only needed if you also need to call this elsewhere, e.g. from AdHoc Sql
CREATE PROC dbo.OuterTransactional
AS
BEGIN
BEGIN TRY
BEGIN TRAN
EXEC dbo.InnerNonTransactional
COMMIT TRAN
END TRY
BEGIN CATCH
-- Rollback and handling code here.
END CATCH
END;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)