我正在使用C#和ADO.Net以及TransactionScope
在ASP.NET应用程序中运行事务。该事务旨在跨多个表保存一些数据,然后向订阅者发送电子邮件。
问题: 当调用一个在SQL Server 2014中有自己的事务的存储过程时,是否可以在TransactionScope
中使用它?还是应该从被调用的存储过程中删除SQL事务语句,如begin tran
、commit tran
和rollback tran
语句?
以下是此场景的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);
}
存储过程 SaveEmailData
的 T-SQL:
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
ROLLBACK TRAN
将撤消连接上执行的任何其他工作,即使是ADO。只有使用SAVEPOINT
才能限制ROLLBACK的范围。但请注意,SavePoints无法与分布式事务一起使用,这可能会在TransactionScope中非常微妙地发生,例如,如果您同时在范围内打开多个连接。我发现在由.Net应用程序调用的SPROC中保留BEGIN/COMMIT TRAN
的唯一原因是如果还需要从SSMS等处以ad-hoc方式执行SPROC。 - StuartLC.Net
控制事务。还可以通过SqlClient使用SavePoints。 - StuartLC