Я разрабатываю Data Access Layer, используя NHibernate. Он будет использоваться в моем бизнес-логическом слое. Мое приложение представляет собой набор нескольких других приложений (ASP.NET MVC, Windows Services, Windows Forms, ASP.NET Web API), все они будут использовать один и тот же бизнес-логический уровень. Уровень бизнес-логики достигнет уровня доступа к данным. Приложения НЕ будут напрямую обращаться к Уровню доступа к данным.NHibernate: В какой сфере я должен использовать транзакцию?
Я знаю, что я НЕ должен зависеть от неявной транзакции и должен включать все вызовы базы данных (включая вызовы READ) в явной транзакции.
В моем понимании транзакция должна быть короткой. Если он живет долго, это может создать проблемы. См. 1 и 2.
Многие ресурсы (на StackOverflow и другие сайты) предлагают заключать код транзакции в блоке using
. Это действительно имеет смысл, поскольку помогает использовать явную транзакцию для каждого вызова базы данных. Это также помогает сделать транзакцию коротким. Проблема с этим подходом заключается в том, что пакетная обработка ограничена только блоком using
. UnitOfWork
не используется в полной мере.
С другой стороны, многие ресурсы (на StackOverflow и других сайтах) предлагают использовать транзакцию на каком-то более высоком уровне, например web-request
(сеанс на запрос) в веб-приложении или «для оконных форм» в WinForms и т. Д. Это улучшает пакетную обработку запросов и лучше использовать UnitOfWork
. Проблема с этим подходом заключается в том, что транзакции долговечны.
Путь 1] Вывести транзакцию в приложение и позволить ему обрабатывать ее.
Вариант 1 - Абонент может справиться с этим на уровне запроса. Недостатком этого подхода является то, что транзакции могут быть долговечными.
Вариант 2 - Если он этого не делает, единственный способ - обработать его на более низком уровне, например, «на метод» или «на небольшой блок кода». Но теперь он должен убедиться, что он начинает транзакцию и совершает/откатывает ее должным образом. Это уменьшает читаемость, сложно пересмотреть код и отладить его в случае возникновения проблем. Кроме того, если это все равно должно быть на более низком уровне, почему бы не включить это в бизнес-логику?
Путь 2] Управляющая транзакция внутри бизнес-логики.
Это делает все сделки недолговечными. Но это не выгодно для дозирования или UnitOfWork
. BLL может не знать заранее, как вызовы базы данных будут выполняться при вызове приложения.
Место, где требуется Begin
и Commit
сделка, которая будет выгодна для дозирования и почитания UnitOfWork
?
Edit 1: (После принятия ответа)
Я только что нашел отличную article на UnitOfWork
. Ниже приведены некоторые из выдержек из них:
Не используйте антипаттерн для сеанса за сеансом: не открывайте и не закрывайте сеанс для каждого простого вызова базы данных в одном потоке. То же самое верно для транзакций базы данных. Вызов базы данных в приложении производится с использованием запланированной последовательности; они сгруппированы в атомные единицы работы.Это также означает, что автоматическая фиксация после каждого отдельного оператора SQL бесполезна в приложении, так как этот режим предназначен для работы с SQL-консолью ad-hoc.
Операции с базой данных никогда не являются обязательными. Вся связь с базой данных должна происходить внутри транзакции. Следует избегать поведения в режиме автоматической фиксации данных для чтения, поскольку многие небольшие транзакции вряд ли будут работать лучше, чем одна четко определенная единица работы. Последняя также более удобна и расширяема.
Наиболее распространенный шаблон в многопользовательском клиент-серверном приложении - это сеанс за запрос. В этой модели запрос от клиента отправляется на сервер, где выполняется уровень сохранения Hibernate. Открывается новый сеанс Hibernate, и все операции с базой данных выполняются в этой части работы. По завершении работы, и после того, как был подготовлен ответ для клиента, сеанс очищается и закрывается. Используйте единую транзакцию базы данных для обслуживания запроса клиентов, начиная и фиксируя ее при открытии и закрытии сеанса. Отношения между ними взаимно однозначны, и эта модель идеально подходит для многих приложений.
Шаблон сеанса за запрос не является единственным способом проектирования единиц работы. Многие бизнес-процессы требуют целого ряда взаимодействий с пользователем, чередующихся с доступом к базе данных. В веб-приложениях и корпоративных приложениях недопустимо, чтобы транзакция базы данных охватывала взаимодействие с пользователем.
База данных или система, границы транзакций всегда необходимы. Никакая связь с базой данных не может произойти за пределами транзакции базы данных (это, похоже, путает многих разработчиков, которые привыкли к режиму автоматической фиксации). Всегда используйте четкие границы транзакций, даже для операций только для чтения. В зависимости от уровня изоляции и возможностей базы данных это может не потребоваться, но нет недостатков, если вы всегда четко разделяете транзакции. Конечно, одна транзакция с базой данных будет работать лучше, чем многие мелкие транзакции, даже для чтения данных.
Как вы очерчиваете свои варианты использования? Вы используете что-то вроде команд или обработчиков? Они могут формировать естественные границы транзакций. Кроме того, вы можете украсить их, чтобы уменьшить шум. –
также сеанс в форме не имеет большого смысла. Вам действительно нужна единица работы. это легко в веб-среде, потому что запрос является естественной единицей работы. формы там, где это становится немного сложнее, потому что, как @DavidOsborne упоминает, ваши примеры использования/истории должны определять ваши транзакционные границы. – Fran
Также стоит исследовать «сеанс для разговора» и связанные с ним шаблоны. –