将 SQL Server 事务作为参数传递的最佳方法是什么



我知道使用"using"关键字和如下代码在.net C#中实现SQL Server事务的解决方案:

InsertDetails()
{
using (TransactionScope ts = new TransactionScope()) 
{    
InsertName();//SQL functions to insert name into name table   
Insertaddress();//SQL functions to insert address into address table
InsertPhoneNo();//SQL functions to insert phone number into contact table
ts.Complete();    
}    
}

但是,例如,我希望将sql服务器事务作为参数传递给不同数据库查询的许多不同函数,而无需使用使用语句示例。

在调用代码路径中的所有函数后,我想调用以提交数据,如果出现问题,则执行回滚。

伪代码如下所示

InsertDetails()
{
var transaction = new Transaction();
var sqlcon = new SqlConnection();    
InsertName(transaction, sqlcon);//SQL functions to insert name into name table  
Insertaddress(transaction, sqlcon);//SQL functions to insert address into address table
InsertPhoneNo(transaction, sqlcon);//code to insert phone no into contact table
try
{
ts.commit();       
}
catch(Exception ex)
{
ts.rollback();
}
}

注意 #1:TransactionScope 可以升级为使用 MSDTC,因此使用 SqlTransaction 有利于避免该行为。

注意 #2:默认情况下,事务范围还将使用序列化隔离级别,当行/表锁定可能过于激进时。 因此,您可能希望在使用 TransactionScope 时更改该行为。 有关更多详细信息,请参阅:为什么 System.Transactions TransactionScope 默认为隔离级别可序列化

使用 SqlTransaction

坚持你的伪代码示例,我会重写更多这样的内容:

InsertDetails()
{
using (var sqlcon = new SqlConnection(<connectionString>))
{
sqlcon.Open();
// Create transaction to be used by all commands.
var transaction = sqlcon.BeginTransaction();
try
{
InsertName(transaction, sqlcon);//SQL functions to insert name into name table  
Insertaddress(transaction, sqlcon);//SQL functions to insert address into address table
InsertPhoneNo(transaction, sqlcon);//code to insert phone no into contact table
transaction.commit();       
}
catch(Exception ex)
{
transaction.rollback();
throw;
}
}
}
// Typical method implementation.
private void InsertName(SqlTransaction transaction, SqlConnection sqlcon)
{
using (var cmd = sqlcon.CreateCommand())
{
// This adds this command to the transaction.
cmd.Transaction = transaction;
// The rest is fairly typical.
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "InsertStoredProcedureName";
... set parameters etc.
cmd.ExecuteNonQuery();
... handle any OUTPUT parameters etc.
}
}

这将回滚任何被调用方法中所有错误的事务。

我不推荐这种方法。

如果您using new TransactionScope那么您只需要在一切正常时致电完成即可。 如果没有,那么如果不调用 Complete,所有内容都将回滚。 所以有点违背了传递交易的目的,不是吗?在我看来,这种语法更清晰。

如果需要确定是否在事务上下文下运行,则可以调用 Transaction.Current 来获取当前事务。

以下模式适用于我 DataContext(使用 Sql Server Profiler 确认(。 你可以用 SqlConnection 替换 DataContext。 这不会导致将事务升级到 MSDTC。 如果事务范围内存在异常或 return 语句,则事务将自动回滚。

using (MyDataContext dc = new MyDataContext(MyConnectionString))
{
using (var t = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted }))
{
InsertName(dc);
InsertAddress(dc);
InsertPhoneNo(dc);
t.Complete();
}
}
void InsertName(MyDataContext dc)
{
dc....
dc.SubmitChanges();
}

不确定,但我们可以简单地这样使用!还有其他问题吗?

using (TransactionScope scope = new TransactionScope())
{
var isSuccess = Save();
var isSuccess2 = Save2();
if (isSuccess && isSuccess2 )
{
scope.Complete();
}
}

相关内容

最新更新