NHibernate: В каком объеме я должен использовать транзакцию?

Я разрабатываю уровень доступа к данным с использованием NHibernate. Он будет использоваться в моем слое бизнес-логики. Мое приложение представляет собой набор из нескольких других приложений (ASP.NET MVC, Windows Services, Windows Forms, ASP.NET Web API), которые все будут использовать один и тот же уровень бизнес-логики. Слой бизнес-логики получит доступ к уровню доступа к данным. Приложения НЕ будут обращаться к слою доступа к данным напрямую.

Мне известно, что я НЕ должен зависеть от неявной транзакции и должен включать все вызовы базы данных (включая вызовы READ) в явную транзакцию.

В моем понимании транзакция должна быть недолгой. Если он живет долго, это может создать проблемы. См. 1 и 2.

Многие ресурсы (на Stackru и других сайтах) предлагают заключать код транзакции в using блок. Это действительно имеет смысл, поскольку помогает использовать явные транзакции для каждого вызова базы данных. Это также поможет сделать транзакцию недолгой. Проблема с этим подходом заключается в том, что дозирование ограничено using блокировать только UnitOfWork не полностью используется.

С другой стороны, многие ресурсы (на Stackru и других сайтах) предлагают использовать транзакции на более высоком уровне, таком как web-request (сеанс по запросу) в веб-приложении ИЛИ "по форме окна" в WinForms и т. д. Это улучшает пакетирование запросов и помогает лучше использовать преимущества UnitOfWork шаблон. Проблема с этим подходом заключается в том, что транзакции являются долгоживущими.

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

Вариант 1 - Абонент может справиться с этим на уровне запроса. Недостаток этого подхода заключается в том, что транзакции могут быть долгоживущими.

Вариант 2 - Если он этого не делает, единственный способ - обрабатывать его на более низком уровне, например, "на метод" или "на небольшой блок кода". Но теперь он должен убедиться, что он начинает транзакцию, и зафиксировать / откатить ее правильно. Это снижает удобочитаемость, затрудняет проверку кода и отладку в случае возникновения проблем. Кроме того, если это все равно должно быть на более низком уровне, почему бы не включить его в бизнес-логику?

Способ 2] Управление транзакциями внутри уровня бизнес-логики.

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

Какое место рекомендуется Begin а также Commit сделка, которая будет использовать преимущества пакетирования и почитания UnitOfWork?

Изменить 1: (после принятия ответа)

Я только что нашел отличную статью о UnitOfWork, Ниже приведены некоторые выдержки из того же:

Не используйте антипаттерн сеанса для каждой операции: не открывайте и не закрывайте сеанс для каждого простого вызова базы данных в одном потоке. То же самое верно для транзакций базы данных. Вызовы базы данных в приложении выполняются с использованием запланированной последовательности; они сгруппированы в атомные единицы работы. Это также означает, что автоматическая фиксация после каждого отдельного оператора SQL в приложении бесполезна, поскольку этот режим предназначен для специальной консольной работы SQL.

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

Наиболее распространенным шаблоном в многопользовательском клиент-серверном приложении является сеанс на запрос. В этой модели запрос от клиента отправляется на сервер, где выполняется постоянный уровень Hibernate. Открывается новый сеанс Hibernate, и все операции с базами данных выполняются в этой единице работы. По завершении работы и после подготовки ответа для клиента сеанс сбрасывается и закрывается. Используйте одну транзакцию базы данных для обслуживания запроса клиента, запуска и принятия его при открытии и закрытии сеанса. Отношения между ними однозначны, и эта модель идеально подходит для многих приложений.

Шаблон сеанса для запроса - не единственный способ проектирования единиц работы. Многие бизнес-процессы требуют целого ряда взаимодействий с пользователем, которые чередуются с доступом к базе данных. В веб-приложениях и корпоративных приложениях недопустимо, чтобы транзакция базы данных охватывала взаимодействие с пользователем.

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

1 ответ

Решение

Почему бы не сделать транзакцию службы (ей) осведомленной?

что-то вроде

    protected virtual TResult Transact<TResult>(Func<TResult> func)
    {
        if (_session.Transaction.IsActive)
            return func.Invoke();

        TResult result;
        using (var tx = _session.BeginTransaction(IsolationLevel.ReadCommitted))
        {
            result = func.Invoke();
            tx.Commit();
        }

        return result;
    }

    protected virtual void Transact(System.Action action)
    {
        Transact(() =>
        {
            action.Invoke();
            return false;
        });
    }

в вашем сервисе или репо, который проверяет, активна ли транзакция и участвует ли в активной, или создает новую транзакцию, если она не существует.

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

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