事务范围选项 - Required 或 RequiresNew

15

目前我对TransactionScope对象的构造函数有些困惑。

假设我的网站用户可以订购产品。在提交请求时,我会验证当前剩余数量,如果仍大于零,则执行请求。最后,我会减少当前剩余量。

整个过程都在使用.NET TransactionScope事务。

在阅读了几篇关于.NET TransactionScope对象的文章之后,我现在有点困惑该在TransactionScope的构造函数中使用哪种TransactionScopeOption值才更合适。

以下哪一项更适合上述情况:

public void ProcessRequest()  
 {  
     TransactionOptions transactionOptions = new TransactionOptions();  
     transactionOptions.IsolationLevel = IsolationLevel.Serializable;  
     using (TransactionScope currentScope = new TransactionScope(TransactionScopeOption.RequiresNew, transactionOptions)) {  
      // DB Query to verify if quantity is still greater than zero  
      // DB Query to request and decrement quantity 
      currentScope.Complete();
     }  
 }  

或者

public void ProcessRequest()  
 {  
     TransactionOptions transactionOptions = new TransactionOptions();  
     transactionOptions.IsolationLevel = IsolationLevel.Serializable;  
     using (TransactionScope currentScope = new TransactionScope(TransactionScopeOption.Required, transactionOptions)) {  
      // DB Query to verify if quantity is still greater than zero  
      // DB Query to request and decrement quantity 
      currentScope.Complete();
     }  
 }  
注意,上述只是我实际问题的过度简化。我只对这种情况下 TransactionScopeOption 的正确值感兴趣 (RequiresNewRequired)。

谢谢回复。

2个回答

17

这取决于您希望在另一个事务内部调用ProcessRequest时发生什么:

public void SomeOtherMethod() {
    using (TransactionScope ts = new TransactionScope()) {
        // Another DB action
        ProcessRequest();
        // Yet another DB action
    }
}
如果你希望 ProcessRequest 使用由 SomeOtherMethod 创建的事务,请使用 TransactionScope.Required。这是默认值(即使在调用时没有创建其他事务作用域,它仍会创建一个事务)。
如果你想强制该方法始终使用自己的(新)事务,请使用 TransactionScope.RequiresNew

在我的情况下,ProcessRequest方法本身永远不会参与到另一个事务中。我只是想确保在请求执行后:“DB查询以验证数量是否仍大于零”在执行:“DB查询以请求并减少数量”时,由于另一个请求执行了相同的ProcessRequest方法,数量尚未达到零。因此,我猜默认值TransactionScope.Required对我来说是正确的选择。 - Abhisheik Coomar Motee
2
否则的话,你会(无意中)暗示ProcessRequest有一些特殊之处,需要使用自己的事务。 - Jeff Sternal

13

我知道你的方法不会在另一个事务中被调用。但是如果它将被调用,以下是如何选择TransactionScopeOption

如果由ProcessRequest写入数据库的内容不能被任何调用者撤销,则使用RequiresNew,它开始一个新的事务并行于调用者(如果有)创建的事务之一,并且新事务不会以任何方式由调用者管理。最好认为事务不能嵌套,要么使用现有事务,要么创建一个新事务。 事务不嵌套!

如果由ProcessRequest写入数据库的内容可以被覆盖,则使用Required。然而,这个选项不透明; 调用ProcessRequest的调用方必须意识到ProcessRequest可能会回滚,因为如果被调用方回滚环境事务,则调用者无法执行任何SQL操作,否则将抛出异常"The operation is not valid for the state of the transaction."。最好在运行任何查询之前始终检查System.Transactions.Transaction.Current.TransactionInformation.Status,因为您不知道是否有任何被调用方秘密创建了事务并将其回滚。

你可能会发现以下表格有用。 enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接