TransactionScopeOption - Required or RequiresNew
I'm currently having a confusion concerning the constructor of the TransactionScope object.
Say that users of my website can order products. On submitting their request, I carry out a verification of the current quantity left and if it is still greater than zero, I carry out the request. Then, at the end I decrement the current quantity left.
The whole process is within a transaction, using .NET transactionScope.
After reading several articles on .NET transactionScope object, I'm now a bit confused about the value of the TransactionScopeOption to use for the constructor of the transactionScope.
Which one of the following is more appropriate for the case described above:
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();
}
}
开发者_如何学运维
OR
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();
}
}
Note that the above is just an over simplification of my actual problem. I'm only interested in knowing the right value of the TransactionScopeOption (RequiresNew or Required) for such a case.
Thanks for replying.
It depends what you want to happen if another method calls ProcessRequest
inside another transaction:
public void SomeOtherMethod() {
using (TransactionScope ts = new TransactionScope()) {
// Another DB action
ProcessRequest();
// Yet another DB action
}
}
If you want ProcessRequest
to use the transaction created by SomeOtherMethod
, use TransactionScope.Required
. This is the default (and it still creates a transaction when you call it without having created another transaction scope up the call stack).
If you want it to force this method to always use its own (new) transaction, use TransactionScope,RequiresNew
.
I understand your method won't be called in another transaction. But in case it will, here is how you choose TransactionScopeOption
.
If the content written to database by ProcessRequest cannot be overturned by any caller, use RequiresNew
, which starts a new transaction parallel to the one created by the caller(if any), and the new transaction is not managed by the caller by any means. It's best to think transaction cannot be nested, either use existing transaction or create a new one. Transaction is not nested!
If the content written to database by ProcessRequest can be overturned, use Required
. However, this option is not transparent; caller to ProcessRequest must be aware that ProcessRequest may roll back because if callee rolls back the ambient transaction, caller cannot perform any sql operation, otherwise exception "The operation is not valid for the state of the transaction." will be thrown. It's probably best to always check System.Transactions.Transaction.Current.TransactionInformation.Status
before running any query as you won't know if any callee furtively created a transaction and rolled it back.
You may find the following table useful.
精彩评论