[英]Using TransactionScope around a stored procedure with transaction in SQL Server 2014
我正在使用C#和ADO.Net與TransactionScope
在ASP.Net應用程序中運行事務。 此事務應該在多個表中保存一些數據,然后向訂閱者發送電子郵件。
問題 :當它包含對SQL Server 2014中具有自己的事務的存儲過程的調用時,它是否是對TransactionScope
的有效使用,或者是否應該從存儲中刪除SQL事務語句,即begin tran
, commit tran
和rollback tran
語句在此TransactionScope
中調用的過程?
下面提到了此場景的C#代碼以及存儲過程的T-SQL代碼。
使用TransactionScope
C#代碼:
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-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
是的,在包裝TSQL BEGIN / COMMIT TRANSACTION
或ADO SqlConnection.BeginTransaction
時, TransactionScope
仍然可以工作。 包裝單個連接時,行為類似於在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外部事務包裝),具體地說, BEGIN CATCH
塊中的ROLLBACK
將中止整個外部事務並且可能會進一步導致由於未遵守@@TRANCOUNT
規則,因此外部TransactionScope
錯誤。 如果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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.