我知道使用“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 server事务作为参数传递给不同数据库查询的许多不同函数,而不使用using语句示例。
在调用代码路径中的所有函数之后,我想调用提交数据,如果出现问题,则执行回滚。
伪代码看起来像这样
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();
}
}
答案 0 :(得分:5)
注意#1:TransactionScope可以升级为使用MSDTC,因此使用SqlTransaction可以避免这种行为。
注意#2:默认情况下,TransactionScope也会使用序列化隔离级别,这可能会在行/表锁定中过于激进。因此,您可能希望在使用TransactionScope时更改该行为。有关详细信息,请参阅:Why is System.Transactions TransactionScope default Isolationlevel Serializable
使用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.
}
}
这将回滚任何被调用方法中的所有错误的事务。
答案 1 :(得分:1)
我不推荐这种方法。
如果您是using new TransactionScope
,那么只要一切都好,您就需要致电完成。如果没有,那么如果未调用Complete,则所有内容都将回滚。所以有点打败传递交易的目的,不是吗?在我看来,这种语法更清晰。
如果您需要确定是否在事务上下文中运行,可以调用Transaction.Current来获取当前事务。
答案 2 :(得分:0)
以下模式对我来说适用于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();
}