2016-06-28 32 views
0

说我有说我执行使用ExecuteNonQuery(DbCommand)从C#在Web应用程序下面的SQL语句执行一个SQL块没有中断

DECLARE @InsertedProductID INT -- this is passed as a parameter 
DECLARE @GroupID INT -- this is passed as a parameter 
DECLARE @total INT 
SET @total = (SELECT COUNT (*) FROM Products WHERE GroupID = @GroupID) 
UPDATE Products SET ProdName = 'Prod_'+ CAST(@total as varchar(15)) 
WHERE ProductID = @InsertedProductID 

我的问题是,我想,以确保整个块执行在一。我的目标是每个组都有独特的ProdName。如果我按照原样保留所有内容,如果insert发生在获取@total和执行UPDATE之间,我很可能会得到重复的产品名称。有没有办法确保整个SQL块不中断地立即执行。 execsp_executesql会实现这个吗?我最后的办法是在ExecuteNonQuery(DbCommand)周围放一个lock但我不喜欢这样做,因为它会造成瓶颈。我不认为使用sql事务在这里是有帮助的,因为我不担心命令的完整性,我很担心命令的并行性。

回答

3

通常,任何DML语句(UPDATE/INSERT/DELETE)都会在特定表上放置一个锁(行级别/表级别),但如果要明确保证操作不应干扰其他执行语句,则应考虑将该整个一个事务块说

Begin transaction 
begin try 
DECLARE @InsertedProductID INT -- this is passed as a parameter 
DECLARE @GroupID INT -- this is passed as a parameter 
DECLARE @total INT 
SET @total = (SELECT COUNT (*) FROM Products WHERE GroupID = @GroupID) 
UPDATE Products SET ProdName = 'Prod_'+ CAST(@total as varchar(15)) WHERE ProductID = @InsertedProductID 

commit; // commits the transaction 
end try 
begin catch 
rollback; //Rolls back the transaction 
end catch 
end 

你也应该考虑使Transaction Isolation LevelREAD COMMITTED避免dirty reads内部SQL块。此外,很明显你应该在stored procedure包装这整个逻辑而执行它们为adhoc SQL

3

如果你有你的创作对象的SqlConnection的控制,可考虑依靠使用Transactions和适当IsolationLevel数据库锁。例如,使用“快照”将导致在提交发生之前单独的事务触及数据时提交的第二个事务失败。

喜欢的东西:

var c = new SqlConnection(...); 
var tran1 = c.BeginTransaction(IsolationLevel.Snapshot); 
var tran2 = c.BeginTransaction(IsolationLevel.Snapshot); 
DoStuff(c, tran1);//Touch some database data 
tran1.Commit(); 
DoStuff(c, tran2);//Change the same data 
tran2.Commit();//Error! 
1

不那么肯定你不能只是这样做

UPDATE Products 
SET ProdName = 'Prod_'+ CAST((SELECT COUNT (*) 
           FROM Products 
           WHERE GroupID = @GroupID) as varchar(15)) 
WHERE ProductID = @InsertedProductID 

但对我来说这是一个奇怪的更新

1

使用事务是正道走。与其他答案一起,您还可以使用TransactionScopeTransactionScope隐式地将连接和SQL命令注册到事务中。如果由于TransactionScope位于使用块中而出现问题,则会自动发生回滚。

实施例:

 try 
     { 
      using (var scope = new TransactionScope()) 
      { 
       using (var conn = new SqlConnection("your connection string")) 
       { 
        conn.Open(); 
        var cmd = new SqlCommand("your SQL here", conn); 
        cmd.ExecuteNonQuery(); 
       } 

       scope.Complete(); 
      } 
     } 
     catch (TransactionAbortedException ex) 
     { 

     } 
     catch (ApplicationException ex) 
     { 

     }