Внутренний TransactionScope с различным IsolationLevel, как это может быть достигнуто?

В текущей реализации TransactionScope отсутствует возможность изменения IsolationLevels во вложенных областях.

Состояния MSDN: при использовании вложенных объектов TransactionScope все вложенные области должны быть настроены на использование одинакового уровня изоляции, если они хотят присоединиться к внешней транзакции. Если вложенный объект TransactionScope пытается присоединиться к внешней транзакции, но при этом он указывает другой уровень изоляции, создается исключение ArgumentException.

Однако SQL Server позволяет нам изменять уровни изоляции в любое удобное для вас время, почему TransactionScope не позволяет? Я не понимаю

Существуют ли в BCL стандарты для вложенных транзакций SQL и их уровней изоляции, запрещающие такое поведение. Какие у меня варианты? Я, конечно, не могу проектировать библиотеки классов и продвигать вместе с ними уровни изоляции только ради того, чтобы их можно было использовать.

Если метод A() хочет уровень Snapshot и вызывает метод B(), который хочет уровень Read Committed. Метод A() находится в LibraryA, который разработан мной, метод B() находится в LibraryB, который разработан фиктивной компанией. Как A() может вызвать B(), не получая ArgumentException?

3 ответа

Решение

Это больше вопрос теории, чем какого-либо конкретного продукта. По сути, исходное понятие транзакции - это то, что имеет все свойства ACID: атомарный, согласованный, изолированный и устойчивый.

http://databases.about.com/od/specificproducts/a/acid.htm

Теперь рассмотрим, что имеется в виду под "уровнем изоляции": по существу, для производительности или по другим причинам мы можем отказаться от некоторых или всех гарантий, которые база данных дает в отношении ACIDity. Изоляция и атомарность тесно связаны между собой, подобно двойственности друг друга. Сломай одного, а другой страдает.

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

Теперь, если какая-то часть вашей транзакции требует большей степени изоляции, тогда вся транзакция также делает это, иначе она может прерваться во время чувствительной части. И наоборот, если какой-либо части предоставляется более низкий уровень изоляции, то вполне может быть, что для правильного функционирования этой части требуется меньшая изоляция. (Не просите меня привести хороший пример того, когда это может быть правдой.)

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

Что действительно должно произойти, так это то, что люди разрабатывают нужные им транзакции. Я понимаю, что это не всегда легко, но в свете того факта, что ваша схема бизнес-данных принадлежит только вам, непросто соединить случайные компоненты SQL вместе.

В случае работы с централизованными базами данных (например, SQL Server) рекомендуется разрабатывать целые транзакции, а затем, когда вы заметите общность проектов, вы можете выделить их, возможно, до того, как начнете писать проблемный код.

Если вам действительно необходимо координировать действия между различными хранилищами данных (или аналогичными), тогда необходим распределенный менеджер транзакций. Это отдельный продукт, и получить его еще сложнее, чем сервер базы данных. Но это необходимо для таких вещей, как банкоматы, которые либо дают вам деньги, либо нет, и которые либо попадают на ваш банковский счет, либо нет, и эти два должны совпадать.

Удачи!

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

проверить этот стека

прочитайте изоляционные замечания

Да. Вы можете вложить TransactionScopesс разным уровнем изоляции.

Как говорится в вашей цитате

все вложенные области должны быть настроены на использование одного и того же уровня изоляции, если они хотят присоединиться к внешней транзакции.

Так что если Bможет потребоваться другой уровень изоляции, чем внешняя транзакция, просто убедитесь, что она не присоединяется к внешней транзакции, с TransactionScopeOption.RequiresNew

      void A()
{
    var options = new TransactionOptions() 
    {
        IsolationLevel = IsolationLevel.Snapshot 
    }
    using (var transaction = new TransactionScope(TransactionScopeOption.Required, options))
    {
        B();
    }

}

void B()
{
    var options = new TransactionOptions()
    {
        IsolationLevel = IsolationLevel.ReadCommitted,
    };
    // RequiresNew is the important bit
    using (var transaction = new TransactionScope(TransactionScopeOptions.RequiresNew, options))
    {
        // Do stuff
    }

}
Другие вопросы по тегам