NHibernate с TransactionScope

Может кто-нибудь дать мне краткий обзор использования TransactionScope с NHibernate? Нужно ли делать что-то особенное с помощью сессии /IEnlistmentNotification/ и т.д. заставить это работать? Есть ли какие-либо подводные камни, о которых я должен волноваться? Например, могу ли я заменить все мои транзакции гибернации:

var transaction = session.BeginTransaction();
try
{
    // code
    transaction.Commit();
}
catch (Exception)
{
    transaction.Rollback();
}

с этим?:

using (var scope = new TransactionScope())
{
    // code
    scope.Complete();
}

6 ответов

Некоторое время я использовал nHibernate 2.1, и после нескольких проблем с производством и пробуя немало вариантов, мы остановились на следующем методе, как избежать утечки соединений с помощью NHibernate And TransactionScope:

        using (var scope = new TransactionScope(TransactionScopeOption.Required))
        {
            using (var session = sessionFactory.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                // do what you need to do with the session
                transaction.Commit();
            }
            scope.Complete();
        }

Так как мы используем MSMQ и WCF, нам пришлось использовать транзакцию окружения.

Мы обнаружили, что не использование session.BeginTransaction() вызвало утечку соединения. Мы также обнаружили, что повторное использование сеанса после фиксации транзакции вызвало состояние гонки (nHibernate не является потокобезопасным, и DTSC-коммиты / откаты происходят в фоновом потоке).

Я тестировал это с помощью разных поставщиков, и это просто работает. Если у вас нет "scope.Complete()", то транзакция будет откатываться. Возможно, вам понадобится MSDTC, на котором запущены машины, если имеется более одного долговременного ресурса. В этом случае MSDTC автоматически обнаружит окружающие транзакции ADO.NET и будет управлять всем этим.

Вышеуказанное работает нормально, если вы используете провайдер соединений, который поддерживает использование облегченного диспетчера транзакций, такого как SQL Server 2005/2008.

Если вы используете SQL Server 7/2000, то все ваши транзакции станут распределенными транзакциями, даже если вы нажмете только одну базу данных / ресурс. Это, вероятно, не то, что вы хотели бы в большинстве случаев, и будет дорогой производительности.

Так что проверьте, подходит ли ваша комбинация провайдера соединений и сервера базы данных для использования с TransactionScope.

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

  • Используйте достаточно свежую версию NHibernate ( > = 3.1).
  • Базовый поставщик данных ADO.NET должен поддерживать TransactionScope (нормально для SQL-Server, Oracle >= 10 с ODP.NET).
  • Создайте сеанс NH в TransactionScope, чтобы обеспечить его зачисление.
  • Ручка промывки NHibernate вручную. Смотрите также здесь и здесь.
  • Подготовьтесь к распределенным транзакциям. Если вы создаете несколько сеансов в одной области, изначально локальная транзакция может быть преобразована в распределенную транзакцию. Я видел, что это происходит даже с теми же строками подключения в БД Oracle 11.2 с использованием ODAC 11.2.0.3.20. На SQL-Server 2008 R2 это не продвигалось. (Кстати, это можно увидеть, посмотрев Transaction.Current.TransactionInformation.DistributedIdentifier, который является нулевым для локальных транзакций.) Хотя распределенные транзакции имеют некоторые преимущества, они более дороги, и их установка требует дополнительных усилий. (Смотрите здесь, как это сделать для Oracle). Чтобы продвижение в Oracle никогда не происходило, установите в строке подключения " Promotable Transaction= local". Это создает исключение, если какой-то код пытается это сделать.

Я надеюсь, что это все;-)

PS: я добавил детали Oracle, потому что они могут принести пользу моей заботе и другим.

По словам Фабио Мауло в комментариях, связанных с NH-2107:

Вы можете использовать TransactionScope, и вам также следует продолжать использовать транзакцию NH. Где вы читали, что использование TransactionScope означает избегание использования транзакции NH?

Я бы предположил, что явное использование транзакций NHibernate не обязательно, но, видимо, это лучшая практика

Кроме того, если вы используете TransactionScope, обновитесь до NHibernate 2.1. Только с 2.1 NH действительно получил хорошую интеграцию с TransactionScope.

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