Sun*_*nil 13 c# sql-server ado.net stored-procedures transactionscope
我正在使用C#和ADO.Net TransactionScope来运行ASP.Net应用程序中的事务.此事务应该在多个表中保存一些数据,然后向订阅者发送电子邮件.
问:这是一个有效的使用TransactionScope,当它包括到在SQL Server 2014年自己的事务存储过程的调用,或者我应该删除SQL事务语句,即begin tran,commit tran并且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);
}
Run Code Online (Sandbox Code Playgroud)
存储过程的T-SQL SaveEmailData:
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
Run Code Online (Sandbox Code Playgroud)
Stu*_*tLC 14
是的,TransactionScope在包装TSQL BEGIN / COMMIT TRANSACTION或ADO 时仍然可以工作SqlConnection.BeginTransaction.包装单个连接时,行为类似于嵌套事务Sql:
@@TranCount 将在每个上增加 BEGIN TRAN
COMMIT TRAN将简单地减少@@TRANCOUNT.只有@@TRANCOUNT达到零时才会提交事务.
然而:
ROLLBACK TRAN将中止整个交易(即@@ TRANCOUNT为零),除非您使用保存点(即SAVE TRANSACTION xx......)ROLLBACK TRANSACTION xx.@@TRANCOUNT从退出SPROC时的连接与输入SPROC时的值不同,则会收到错误.因此,通常更容易将事务语义留下TransactionScope并删除任何手动BEGIN TRAN / COMMIT TRAN逻辑,使您的TSQL 变得混乱.
编辑 - 澄清以下评论
在OP的情况下,SPROC尚未写入时考虑嵌套事务(即,是否裹通过一个SQL或.Net外部事务),具体地,ROLLBACK在BEGIN CATCH块将中止整个外交易并很可能引起在进一步的错误外部TransactionScope因为@@TRANCOUNT规则没有得到遵守.甲嵌套事务图案像这样如果一个SPROC需要在两个嵌套的或独立事务的方式操作应当观察.
SavePoints不适用于分布式事务,并且TransactionScope可以轻松升级到分布式事务,例如,如果您在事务范围内使用不同的连接字符串或控制其他资源.
因此,我建议将PROC重构为一个"快乐"的核心/内部情况,从事务范围调用此内部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;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13599 次 |
| 最近记录: |