在C#循环中调用SQL存储过程时处理事务

在C#循环中调用SQL存储过程时处理事务,c#,sql,sql-server,loops,stored-procedures,C#,Sql,Sql Server,Loops,Stored Procedures,我正在开发一个已经由其他开发人员开发的系统。 在该系统中,他们调用了一个存储过程,用于在C#中的循环侧插入记录,而不使用用户定义的表类型 我需要做的是在这个场景中添加一个事务。但问题是我不知道交易地点 我想知道它是在扭曲循环的C代码中,还是在存储过程中 SQL SERVER中的 BEGIN TRY BEGIN TRAN -- DO YOUR INSERT /UPDATE /DELETE HERE COMMIT TRAN T1 END TRY BEGIN CATCH -- // ROLL

我正在开发一个已经由其他开发人员开发的系统。 在该系统中,他们调用了一个存储过程,用于在C#中的循环侧插入记录,而不使用用户定义的表类型

我需要做的是在这个场景中添加一个事务。但问题是我不知道交易地点

我想知道它是在扭曲循环的C代码中,还是在存储过程中

SQL SERVER中的

BEGIN TRY
BEGIN TRAN 

-- DO YOUR INSERT /UPDATE /DELETE HERE 

COMMIT TRAN T1
END TRY
BEGIN CATCH 
-- // ROLL BACK IF ERROR OCCURS

ROLLBACK TRAN T1
END CATCH
在C中#


你只能把它放在C#loop里面。在过程内启动的事务必须在过程退出之前提交。SQL Server在运行过程之前和之后检查,如果结果不匹配,则引发异常。因此,过程不可能启动必须由调用方提交的事务

最简单的方法是将C代码包装到事务范围中:

using(var scope =  new TransactionScope(
      TransactionScopeOption.Required, 
      new TransactionOptions() {
         IsolationLevel = IsolationLevel.ReadCommitted
      })) {
   // Do the work here
   scope.Complete();
}

请注意,传递
IsolationLevel=IsolationLevel.ReadCommitted
是。

在这种情况下,事务需要在C代码中开始,您有以下选项:

  • 使用
    连接对象中的
    事务

    using (var conn = new SqlConnection(connString))
    {
    conn.Open();
    using (IDbTransaction tran = conn.BeginTransaction())
    {
        try
        {
            // transactional code...
            using (SqlCommand cmd = conn.CreateCommand())
            {
                // Loop the Insert operation here 
                cmd.CommandText = "INSERT Operation";
                cmd.Transaction = tran as SqlTransaction;
                cmd.ExecuteNonQuery();
            }
            tran.Commit();
        }
        catch(Exception ex)
        {
            tran.Rollback();
            throw;
        }
    }
    }
    
  • 使用隐式或显式环境事务
  • 使用
    TransactionScope
    (隐式)环境事务(在异常情况下是自动回滚)

    • 使用
      committeabletransaction
      (显式)环境事务

      var tran = new CommittableTransaction();
      using (var conn = new SqlConnection(connString))
      {
       conn.Open();
      try
      {
         conn.EnlistTransaction(tran);
      
      using (SqlCommand cmd = conn.CreateCommand())
      {
          // Loop the Insert operation here 
          cmd.CommandText = "INSERT Operation";
          cmd.ExecuteNonQuery();
      }   
        tran.Commit();
      }   
      catch(Exception ex)
       {
          tran.Rollback();
          throw;
       }          
      } 
      
对于
环境事务
,请记住,如果您打开多个连接,那么它将从
本地事务升级到全局事务
,因此需要
MSDTC
,这会影响性能

检查以下链接:

只有当所有插入/DML都发生在同一事务上下文中时,这两个(Sql Server,C#)才是相同的,因为插入是多次往返的。要使两者相同,就需要使用TVP
using (var scope =  new TransactionScope(
     TransactionScopeOption.Required, 
     new TransactionOptions() {
     IsolationLevel = IsolationLevel.ReadCommitted
   }))
{
using (var conn = new SqlConnection(connString))
{
   conn.Open();

    using (SqlCommand cmd = conn.CreateCommand())
    {
        // Loop the Insert operation here 
        cmd.CommandText = "INSERT Operation";
        cmd.ExecuteNonQuery();
    }                
}    
 scope.Complete();
} 
var tran = new CommittableTransaction();
using (var conn = new SqlConnection(connString))
{
 conn.Open();
try
{
   conn.EnlistTransaction(tran);

using (SqlCommand cmd = conn.CreateCommand())
{
    // Loop the Insert operation here 
    cmd.CommandText = "INSERT Operation";
    cmd.ExecuteNonQuery();
}   
  tran.Commit();
}   
catch(Exception ex)
 {
    tran.Rollback();
    throw;
 }          
}