Если вы поместите @Transactional
в DAO
классах и / или их методы или лучше аннотировать классы услуг , которые призывают с помощью объектов DAO? Или имеет смысл аннотировать оба «слоя»?
java
spring
annotations
transactions
dao
Томас Эйнваллер
источник
источник
В целом я согласен с другими, утверждая, что транзакции обычно начинаются на уровне обслуживания (конечно, в зависимости от степени детализации, которая вам требуется).
Тем не менее, в то же время я также начал добавлять
@Transactional(propagation = Propagation.MANDATORY)
к своему уровню DAO (и другим уровням, которым не разрешено запускать транзакции, но требуются существующие), потому что намного легче обнаружить ошибки, когда вы забыли начать транзакцию в вызывающей стороне ( например, услуга). Если ваш DAO аннотирован обязательным распространением, вы получите исключение, указывающее, что при вызове метода нет активной транзакции.У меня также есть интеграционный тест, в котором я проверяю все bean-компоненты (постпроцессор bean-компонентов) на наличие этой аннотации и завершаю работу, если есть
@Transactional
аннотация с распространением, отличным от Mandatory, в bean-компоненте, который не принадлежит уровню сервисов. Таким образом я убеждаюсь, что мы не запускаем транзакции не на том слое.источник
@Transactional
класс реализации Service, и я должен включить реализацию класса@Transactional(propagation = MANDATORY)
DAO (хранилище)?Транзакционные аннотации должны размещаться вокруг всех операций, которые неотделимы.
Например, ваш звонок «сменить пароль». Это состоит из двух операций
Таким образом, в вышеприведенном случае, если проверка завершится неудачно, то также может произойти сбой смены пароля? Если это так, то транзакция должна быть около 1 и 2 (так на уровне обслуживания). Если электронная почта не работает (вероятно, на ней должна быть какая-то защита от сбоев, чтобы она не сработала), то должна ли она отменить изменение пароля и аудит?
Это те вопросы, которые вам нужно задавать при принятии решения о том, где поставить
@Transactional
.источник
Правильный ответ для традиционных архитектур Spring заключается в размещении транзакционной семантики в классах обслуживания по причинам, которые уже были описаны другими.
Весной появляется тенденция к разработке на основе доменов (DDD). Spring Roo прекрасно иллюстрирует эту тенденцию. Идея состоит в том, чтобы сделать POJO объекта домена намного богаче, чем на типичных архитектурах Spring (обычно они анемичны ), и, в частности, поместить семантику транзакций и персистентности в сами объекты домена. В случаях, когда все, что требуется, это простые операции CRUD, веб-контроллеры работают непосредственно с объектами POJO домена (в этом контексте они функционируют как объекты), и уровень обслуживания отсутствует. В случаях, когда требуется некоторая координация между объектами домена, у вас может быть обработчик служебного компонента, который
@Transaction
по традиции. Вы можете установить распространение транзакции на объектах домена примерноREQUIRED
так, чтобы объекты домена использовали любые существующие транзакции, например транзакции, которые были запущены в компоненте службы.Технически эта техника использует AspectJ и
<context:spring-configured />
. Roo использует определения между типами AspectJ, чтобы отделить семантику сущности (транзакции и постоянство) от содержимого объекта домена (в основном, полей и бизнес-методов).источник
Обычным случаем будет аннотирование на уровне сервисного уровня, но это действительно зависит от ваших требований.
Аннотирование на сервисном уровне приведет к более длительным транзакциям, чем аннотирование на уровне DAO. В зависимости от уровня изоляции транзакции, который может вызвать проблемы, так как параллельные транзакции не будут видеть изменения друг друга, например. ПОВТОРЯЕМЫЙ ЧИТАТЬ.
Аннотирование в DAO сделает транзакции настолько короткими, насколько это возможно, с тем недостатком, что функциональность, предоставляемая вашим сервисным уровнем, не будет выполняться в одной транзакции (с возможностью отката).
Не имеет смысла аннотировать оба слоя, если режим распространения установлен по умолчанию.
источник
Я помещаю
@Transactional
на@Service
слой и устанавливаюrollbackFor
любое исключение иreadOnly
оптимизирую транзакцию дальше.По умолчанию
@Transactional
будет выполняться поиск только «RuntimeException
Непроверенных исключений», а при установке отката на «Exception.class
Проверенные исключения» будет выполняться откат для любого исключения.См. « Проверенные и непроверенные исключения» .
источник
Или имеет смысл аннотировать оба «слоя»? - не имеет ли смысла аннотировать и уровень обслуживания, и уровень дао - если кто-то хочет удостовериться, что метод DAO всегда вызывается (распространяется) из уровня обслуживания с распространением "обязательно" в DAO. Это обеспечило бы некоторое ограничение для вызова методов DAO из уровня пользовательского интерфейса (или контроллеров). Кроме того, при модульном тестировании уровня DAO, в частности, аннотирование DAO также гарантирует его тестирование на функциональность транзакций.
источник
propagation=Propagation.REQUIRES_NEW
. В противном случае, в большинстве случаев, включая распространение = обязательное, DAO будет просто участвовать в существующей транзакции, запущенной уровнем обслуживания.Кроме того, Spring рекомендует использовать аннотацию только для конкретных классов, а не для интерфейсов.
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
источник
Для транзакции на уровне базы данных
в основном я использовал
@Transactional
в DAO только на уровне метода, поэтому конфигурация может быть специально для метода / с использованием по умолчанию (обязательно)Метод DAO, который получает выборку данных (выберите ..) - это не нужно,
@Transactional
это может привести к некоторым издержкам из-за перехватчика транзакции / и прокси-сервера AOP, которые также должны быть выполнены.Методы DAO, которые делают вставку / обновление, получат
@Transactional
очень хороший блог о трансакционном
Для уровня приложения -
я использую транзакционную для бизнес-логики, я хотел бы иметь возможность откат в случае непредвиденной ошибки
источник
Transactional
вJava
Обычно нужно поместить транзакцию на уровень сервиса.
Но, как было сказано ранее, атомарность операции - это то, что говорит нам, где необходима аннотация. Таким образом, если вы используете фреймворки, такие как Hibernate, где одна операция «сохранить / обновить / удалить / ... модификацию» над объектом может потенциально изменить несколько строк в нескольких таблицах (из-за каскада через граф объектов) Конечно, также должно быть управление транзакциями по этому конкретному методу DAO.
источник
@Transactional
Аннотации должны быть размещены вокруг всех операций, которые неразделимы. Использование@Transactional
распространения транзакции обрабатывается автоматически. В этом случае, если текущий метод вызывает другой метод, этот метод будет иметь возможность присоединиться к текущей транзакции.Итак, давайте возьмем пример:
У нас есть 2 модели то есть
Country
иCity
. Реляционное сопоставлениеCountry
иCity
модель похожи на то, чтоCountry
можно иметь несколько городов, поэтому сопоставление похоже наЗдесь Страна сопоставлена с несколькими городами с получением их
Lazily
. Таким образом, здесь возникает роль,@Transactinal
когда мы получаем объект Country из базы данных, тогда мы получим все данные объекта Country, но не получим набор городов, потому что мы выбираем городаLAZILY
.Когда мы хотим получить доступ к множеству городов из объекта страны, тогда мы получим нулевые значения в этом наборе, потому что объект набора, созданный только в этом наборе, не инициализируется с этими данными, чтобы получить значения набора, который мы используем,
@Transactional
т.е.Таким образом, в основном
@Transactional
Сервис может сделать несколько вызовов в одной транзакции, не закрывая соединение с конечной точкой.источник
@Transactional
самом делеЛучше иметь его на уровне сервиса! Это ясно объясняется в одной из статей, с которыми я столкнулся вчера! Вот ссылка, которую вы можете проверить!
источник
@Transactional
Следует использовать на уровне услуг , поскольку он содержит бизнес - логику. Уровень DAO обычно имеет только операции CRUD базы данных.Spring doc: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html
источник
Сервисный слой - лучшее место для добавления
@Transactional
аннотаций, так как большая часть бизнес-логики, представленной здесь, содержит поведение на уровне детализации.Предположим, что мы добавляем его в DAO, и из службы мы вызываем 2 класса DAO, один из которых был неудачным, а другой - успешным, в этом случае, если
@Transactional
не в службе, одна БД выполнит фиксацию, а другая откатится.Поэтому я рекомендую использовать эту аннотацию с умом и использовать только на уровне сервиса.
Проект Github - Ява-Алгос
источник
Прежде всего давайте определимся, где мы должны использовать транзакцию ?
Я думаю, что правильный ответ - когда нам нужно убедиться, что последовательность действий будет завершена вместе как одна атомарная операция, или никакие изменения не будут сделаны, даже если одно из действий не выполнится.
Хорошо известна практика внедрения бизнес-логики в сервисы. Поэтому сервисные методы могут содержать разные действия, которые должны выполняться как единая логическая единица работы. Если так - то такой метод должен быть помечен как транзакционный . Конечно, не каждый метод требует такого ограничения, поэтому вам не нужно помечать весь сервис как транзакционный .
И даже больше - не забудьте учесть, что @Transactional, очевидно, может снизить производительность метода. Чтобы увидеть всю картину, вы должны знать уровни изоляции транзакций. Знание этого может помочь вам избежать использования @Transactional там, где это необязательно.
источник
Лучше держать @Transactional на отдельном промежуточном уровне между DAO и Service Layer. Поскольку откат очень важен, вы можете поместить все ваши манипуляции с БД на средний уровень и написать бизнес-логику на уровне обслуживания. Средний слой будет взаимодействовать с вашими слоями DAO.
Это поможет вам во многих ситуациях, таких как ObjectOptimisticLockingFailureException - это исключение возникает только после завершения вашей транзакции. Таким образом, вы не можете поймать его в среднем слое, но теперь вы можете поймать его в слое сервиса. Это было бы невозможно, если у вас есть @Transactional в слое Service. Хотя вы можете поймать контроллер, но контроллер должен быть как можно более чистым.
Если вы отправляете почту или смс в отдельном потоке после выполнения всех параметров сохранения, удаления и обновления, вы можете сделать это в сервисе после завершения транзакции на среднем уровне. Опять же, если вы упомянули @Transactional на уровне сервиса, ваша почта будет отправляться, даже если ваша транзакция не удалась.
Таким образом, наличие среднего слоя @Transaction поможет сделать ваш код лучше и проще в обращении. В противном случае, если вы используете слой DAO, вы не сможете откатить все операции. Если вы используете сервисный уровень, вам, возможно, придется использовать AOP (Aspect Oriented Programming) в некоторых случаях.
источник
В идеале сервисный уровень (менеджер) представляет вашу бизнес-логику, и поэтому он должен быть аннотирован с помощью
@Transactional
.Service layer может вызывать разные DAO для выполнения операций с БД. Предположим, что у вас есть N операций DAO в сервисном методе. Если ваша 1-я операция DAO завершилась неудачно, другие могут все еще быть пропущены, и вы получите несовместимое состояние БД. Слой Annoating Service может спасти вас от таких ситуаций.источник
Я предпочитаю использовать
@Transactional
на уровне услуг на уровне метода.источник
@Transactional
использует на уровне обслуживания, который вызывается с помощью уровня контроллера (@Controller
) и вызова уровня обслуживания к уровню DAO (@Repository
), то есть операции, связанной с базой данных.источник