Тайм-аут транзакции по умолчанию - PullRequest
34 голосов
/ 28 августа 2009

Я использовал для установки тайм-аутов транзакций с помощью TransactionOptions.Timeout , но решил для простоты обслуживания использовать подход конфигурации:

 <system.transactions>
    <defaultSettings timeout="00:01:00" />
  </system.transactions>

Конечно, после установки этого я хотел проверить, что он работает, поэтому сократил время ожидания до 5 секунд, затем запустил тест, который длился дольше, чем это - но транзакция не прерывается! Если я настрою тест для установки значения TransactionOptions.Timeout на 5 секунд, тест будет работать как ожидалось

После расследования я думаю, что проблема, по-видимому, связана с TransactionOptions.Timeout, хотя я его больше не использую.

Мне все еще нужно использовать TransactionOptions, чтобы я мог установить IsolationLevel, но я больше не устанавливаю значение Timeout. Если я смотрю на этот объект после его создания, значение timeout равно 00:00:00, что соответствует бесконечности. Означает ли это, что мое значение, заданное в файле конфигурации, игнорируется?

Подведем итог:

  • нельзя ли смешивать конфиг настройка и использование TransactionOptions
  • Если нет, есть ли любой способ извлечь настройки конфигурации во время выполнения, и используйте это, чтобы установить Тайм-аут свойства
  • [Изменить] ИЛИ Установить уровень изоляции по умолчанию без использования TransactionOptions

Ответы [ 6 ]

46 голосов
/ 28 апреля 2010

Вы можете получить (подтвержденный) тайм-аут по умолчанию из конфигурации, используя TransactionManager.DefaultTimeout.

TransactionOptions - это структура, которая включает в себя время ожидания и уровень изоляции. При инициализации struct с использованием конструктора по умолчанию он всегда будет инициализировать элементы структуры их значениями по умолчанию:

TransactionOptions transactionOptions = new TransactionOptions();
transactionOptions.Timeout == default(TimeSpan); // TimeSpan.Zero
transactionOptions.IsolationLevel == default(IsolationLevel); // IsolationLevel.Serializable

Если вы хотите указать IsolationLevel и использовать время ожидания по умолчанию:

new TransactionOptions()
{
    IsolationLevel = IsolationLevel.Serializable, // Use whatever level you require
    Timeout = TransactionManager.DefaultTimeout
};
46 голосов
/ 02 сентября 2009

Вы можете смешивать параметры конфигурации system.transaction и использование класса TransactionOption, но есть некоторые вещи, о которых вам необходимо знать.

Если вы используете TransactionOption и укажите значение Timeout, это значение будет использоваться над System.Transactions / defaultTimeout значение.

Выше, я думаю, суть проблемы в вашем случае. Вы используете TransactionOption для указания уровня изоляция , и в качестве побочного эффекта вы получаете бесконечное значение тайм-аута, потому что бесконечность является значением времени ожидания по умолчанию для TransactionOption, если его не указан. Хотя я не совсем уверен, почему это так ... имеет смысл установить значение по умолчанию для тайм-аута транзакции по умолчанию.

Вы можете реализовать свой собственный вспомогательный класс TransactionOptions, который включает значения по умолчанию, которые считываются из app.config (если найдены), или значения по умолчанию для разумных значений для класса TransactionOption, который можно использовать.

В любом случае вы все равно можете ограничить это с помощью значения system.transaction / machineSettings / maxTimeout . Это административный параметр, который можно настроить только через machine.config. Вы получите исключение ConfigurationException, если попробуете это из app / web.config.

<system.transactions>
    <machineSettings maxTimeout="00:00:30" />
</system.transactions>

Если установлено значение maxTimeout , независимо от того, какое значение времени ожидания вы укажете, максимальное значение будет ограничено значением maxTimeout. Значение по умолчанию maxTimeout составляет 00:10:00 или 10 минут, поэтому на самом деле у вас никогда не будет бесконечного времени ожидания транзакции.

Вы также можете установить транзакцию IsolationLevel явно для соединения с базой данных, которое вы используете в транзакции. Как то так?

   var connectionString = "Server=.;Database=master;Trusted_Connection=True;";

            using (var scope = new TransactionScope(TransactionScopeOption.Required))
            {
                using (var conn = new SqlConnection(connectionString))
                {
                    conn.Open();
                    var sqlTransaction = conn.BeginTransaction(System.Data.IsolationLevel.Serializable);

                    // do database work
                    //
                    sqlTransaction.Commit();


                }

                // do other work..
                //

                scope.Complete();

            }

При тестировании может потребоваться перестройка, чтобы app.config был перегенерирован. В ходе моего тестирования выяснилось, что мне нужно было прервать процесс * .vshost.exe, чтобы он подхватил изменение настроек конфигурации system.transaction - хотя я чувствую, что это может быть случайностью. Просто к твоему сведению ..

11 голосов
/ 02 января 2013

Для каждого рефлектора основные правила установки времени транзакции с помощью конструкторов TransactionScope следующие:

DefaultTimeOut определяется по первому правилу снизу, которое удовлетворяется:

  • если конструктор имеет параметр TimeSpan, то DefaultTimeout является этим параметром
  • , если конструктор имеет параметр TransactionOption, значение DefaultTimeout равно transactionOption.TimeOut
  • , если в конструкторе есть параметр TransactionScopeOption, значение DefaultTimeout равно scopeOption.TimeOut
  • если конструктор не имеет параметра времени ожидания, DefaultTimeout - это значение, указанное в файле приложения или веб-конфигурации.
  • в противном случае DefaultTimeOut равен 1 минуте.

MaxTimeOut равно 10 минутам, если в файле machine.config не указано другое значение.

Эффективное время ожидания для транзакции меньше значений MaxTimeOut и DefaultTimeOut, больше нуля. Если MaxTimeOut и DefaultTimeOut равны нулю, эффективный тайм-аут представляет собой количество тактов, представленное long.MaxValue (бесконечность).

Если экземпляр TransactionScope не создает новую транзакцию либо из-за того, что транзакция передается в ее конструктор, либо из-за того, что параметр области действия транзакции не требует этого (например, когда присутствует окружающая транзакция и TransactionScopeOption требуется) , но параметр timeOut все еще передается в конструктор, запускается таймер. По истечении времени ожидания вызывается метод TimeOut() базовой транзакции. Свойства DefaultTimeOut и MaxTimeOut в этом случае не используются.

Если transactionScopeOption == TransactionScopeOption.Supress, тайм-аут игнорируется и не оказывает влияния.

Также можно определить MaxTimeOut в файле конфигурации приложения / web, если соответствующий раздел в machine.config переопределен (обратите внимание на значения атрибутов allowDefintion и allowExeDefinition):

<sectionGroup name="system.transactions" type="System.Transactions.Configuration.TransactionsSectionGroup, System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null">
    <section name="defaultSettings" type="System.Transactions.Configuration.DefaultSettingsSection, System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null"/>
    <section name="machineSettings" type="System.Transactions.Configuration.MachineSettingsSection, System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null" allowDefinition="MachineToApplication" allowExeDefinition="MachineToApplication"/>
</sectionGroup>

Для быстрого ознакомления, вот конструкторы TransactionScope:

public TransactionScope(Transaction transactionToUse, TimeSpan scopeTimeout, EnterpriseServicesInteropOption interopOption);
public TransactionScope(TransactionScopeOption scopeOption, TransactionOptions transactionOptions, EnterpriseServicesInteropOption interopOption);
public TransactionScope(TransactionScopeOption scopeOption, TransactionOptions transactionOptions);
public TransactionScope(TransactionScopeOption scopeOption, TimeSpan scopeTimeout);
public TransactionScope(Transaction transactionToUse, TimeSpan scopeTimeout);
public TransactionScope(TransactionScopeOption scopeOption);
6 голосов
/ 05 сентября 2009

Настройка файла конфигурации игнорируется при использовании TransactionOptions. Создание TransactionScope в большинстве случаев создает экземпляр CommittableTransaction. Конструктор no arg в CommittableTransaction будет использовать настройку файла конфигурации в качестве времени ожидания по умолчанию. Конструкторы TransactionScope, которые принимают TransactionOptions или TimeSpan, вызовут одну из перегрузок класса CommittableTransaction, а не версию no arg. Поэтому, если вы хотите использовать это значение, вам нужно взять его из файла конфигурации самостоятельно.

Когда я столкнулся с этим, я поместил следующий код в небольшой класс TransactionOptionsFactory.


Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSectionGroup sectionGroup = configuration.GetSectionGroup("system.transactions");
DefaultSettingsSection defaultSettings = (DefaultSettingsSection) sectionGroup.Sections["defaultSettings"];
TransactionOptions options = new TransactionOptions();
options.Timeout = defaultSettings.Timeout;
options.IsolationLevel = IsolationLevel.ReadCommitted;
2 голосов
/ 26 июля 2013
void Main()
{
    var maximumTimeout = TransactionManager.MaximumTimeout;//This step is necessary to init _maximumTimeout value, 

    FieldInfo fieldInfo = typeof(TransactionManager).GetFields(BindingFlags.NonPublic | BindingFlags.Static).Single(item => item.Name == "_maximumTimeout");
    var customMaximumTimeout = TimeSpan.FromHours(1);
    fieldInfo.SetValue(null, customMaximumTimeout);
    maximumTimeout = TransactionManager.MaximumTimeout;

    Console.WriteLine(maximumTimeout);//01:00:00
    // use TransactionScope
}
1 голос
/ 01 сентября 2009

Чтобы изложить мои текущие мысли:

  • Невозможно смешать настройки конфигурации и использование TransactionOptions
  • Единственный способ извлечь настройки конфигурации во время выполнения - это прочитать app.config в виде файла XML
  • Уровень изоляции по умолчанию можно выполнить только с помощью параметров транзакции или на уровне обслуживания в WCF с использованием атрибутов
...