TransactionScopeOption - требуется или требуется новое

В настоящее время у меня возникает путаница в отношении конструктора объекта TransactionScope.

Скажите, что пользователи моего сайта могут заказывать продукты. При отправке их запроса я выполняю проверку оставшегося количества слева и, если он еще больше нуля, я выполняю запрос. Затем, в конце, я уменьшаю текущую оставшуюся величину.

Весь процесс находится в транзакции, используя .NET transactionScope.

После прочтения нескольких статей об объекте .NET transactionScope, я сейчас немного запутался в значении TransactionScopeOption, которое будет использоваться для конструктора транзакцииScope.

Какое из следующих ниже подходит для случая, описанного выше:

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 (RequiresNew или Обязательный) для такого случая.

Спасибо за ответ.

Ответы

Ответ 1

Это зависит от того, что вы хотите, если другой метод вызывает ProcessRequest внутри другой транзакции:

public void SomeOtherMethod() {
    using (TransactionScope ts = new TrasansctionScope()) {
        // Another DB action
        ProcessRequest();
        // Yet another DB action
    }
}

Если вы хотите, чтобы ProcessRequest использовал транзакцию, созданную с помощью SomeOtherMethod, используйте TransactionScope.Required. Это значение по умолчанию (и оно по-прежнему создает транзакцию, когда вы вызываете ее, не создав другую область транзакций до стека вызовов).

Если вы хотите, чтобы этот метод всегда использовал свою собственную (новую) транзакцию, используйте TransactionScope,RequiresNew.

Ответ 2

Насколько я понимаю, ваш метод не будет вызываться в другой транзакции. Но в этом случае, вот как вы выбираете TransactionScopeOption.

Если содержимое, записанное в базу данных ProcessRequest, не может быть отменено каким-либо вызывающим абонентом, используйте RequiresNew, который запускает новую транзакцию parallel, созданную вызывающим (если есть), и новая транзакция не управляется вызывающим абонентом любыми способами. Лучше думать, что транзакция не может быть вложенной, либо использовать существующую транзакцию, либо создать новую. Транзакция не вложена!

Если содержимое, записанное в базу данных ProcessRequest, может быть опрокинуто, используйте Required. Однако этот вариант не является прозрачным; caller to ProcessRequest должен знать, что ProcessRequest может откатиться, потому что, если вызываемая команда откатывает внешнюю транзакцию, вызывающий не может выполнить какую-либо операцию sql, иначе исключение "Операция недействительна для состояния транзакции". будут выброшены. Вероятно, лучше всегда проверять System.Transactions.Transaction.Current.TransactionInformation.Status перед запуском какого-либо запроса, поскольку вы не будете знать, украден ли какой-либо вызов, и отложил его.

Вы можете найти следующую таблицу полезной. введите описание изображения здесь