Следует ли размещать @Transactional
в классах DAO
и/или их методах или лучше комментировать классы службы, которые вызывают с использованием объектов DAO? Или имеет смысл аннотировать оба "слоя"?
Где принадлежит аннотация @Transactional?
Ответ 1
Я думаю, что транзакции принадлежат слою службы. Это тот, который знает об единицах работы и случаях использования. Это правильный ответ, если у вас несколько DAO, введенных в Службу, которые должны работать вместе в одной транзакции.
Ответ 2
В целом я согласен с другими, заявляя, что транзакции обычно начинаются на уровне обслуживания (в зависимости от требуемой детализации).
Однако в то же время я также начал добавлять @Transactional(propagation = Propagation.MANDATORY)
к моему уровню DAO (и другим уровням, которым не разрешено запускать транзакции, но требуются существующие), потому что гораздо легче обнаружить ошибки, в которых вы забыли начать транзакция в вызывающем абоненте (например, услуга). Если ваш DAO аннотируется с обязательным распространением, вы получите исключение, указав, что при вызове метода нет активной транзакции.
У меня также есть тест интеграции, где я проверяю все beans (bean пост-процессор) для этой аннотации и терпит неудачу, если существует аннотация @Transactional
с распространением, отличным от Mandatory, в bean, которая не принадлежит на уровень услуг. Таким образом, я уверен, что мы не запускаем транзакции на неправильном уровне.
Ответ 3
Транзакционные аннотации должны быть размещены вокруг всех операций, которые неотделимы.
Например, ваш вызов - "сменить пароль". Это состоит из двух операций
- Измените пароль.
- Аудит изменений.
- Отправляйте клиенту сообщение о том, что пароль был изменен.
Итак, в приведенном выше случае, если аудит завершается с ошибкой, тогда смена пароля также не выполняется? Если это так, то транзакция должна быть около 1 и 2 (так что на уровне сервиса). Если сообщение электронной почты не работает (вероятно, должно быть что-то вроде сбоя в безопасности, так что это не сработает), тогда он должен откатить пароль для изменения и аудит?
Вот те вопросы, которые вам нужно задать при выборе места @Transactional
.
Ответ 4
Правильный ответ для традиционных архитектур Spring заключается в размещении транзакционной семантики в классах службы по причинам, которые другие уже описали.
Новая тенденция в Spring относится к доменному проекту (DDD). Spring Roo отлично иллюстрирует тенденцию. Идея состоит в том, чтобы сделать объект POJO домена более более богатым, чем на типичных архитектурах Spring (обычно они anemic) и, в частности, поставить семантику транзакций и персистентности на объекты домена. В тех случаях, когда все, что требуется, - это простые операции CRUD, веб-контроллеры работают непосредственно над объектами POJO домена (они функционируют как сущности в этом контексте), и нет уровня обслуживания. В случаях, когда между объектами домена требуется некоторая координация, вы можете иметь дескриптор службы bean, который с @Transaction
согласно традиции. Вы можете настроить распространение транзакций на объектах домена на нечто вроде REQUIRED
, чтобы объекты домена использовали любые существующие транзакции, такие как транзакции, запущенные в службе bean.
Технически этот метод использует AspectJ и <context:spring-configured />
. Roo использует определения Inter-type AspectJ для разделения семантики объекта (транзакций и персистентности) на предмет объектов домена (в основном на поля и бизнес-методы).
Ответ 5
Нормальным случаем будет аннотация на уровне уровня сервиса, но это действительно зависит от ваших требований.
Аннотирование на уровне сервиса приведет к более длительным транзакциям, чем аннотирование на уровне DAO. В зависимости от уровня изоляции транзакций, который может вызывать проблемы, поскольку параллельные транзакции не видят друг друга, например, напр. ПОВТОРНОЕ ПРОЧИТАНИЕ.
Аннотирование по DAO будет держать транзакции как можно короче, с недостатком того, что функциональность, которую ваш уровень обслуживания обнажает, не будет выполняться в одной транзакции (откатной).
Не имеет смысла аннотировать оба слоя, если для режима распространения установлено значение по умолчанию.
Ответ 6
Я размещаю @Transactional
на уровне @Service
и устанавливаю rollbackFor
любое исключение и readOnly
для дальнейшей оптимизации транзакции.
По умолчанию @Transactional
будет искать только RuntimeException
(Unchecked Exceptions), установив rollback на Exception.class
(Checked Exceptions), он откатится для любого исключения.
@Transactional(readOnly = false, rollbackFor = Exception.class)
Ответ 7
Или имеет смысл аннотировать оба "слоя"? - не имеет смысла аннотировать как уровень сервиса, так и уровень dao - если вы хотите убедиться, что метод DAO всегда вызываемый (распространяемый) из служебного уровня с "обязательным" распространением в DAO. Это обеспечит некоторое ограничение для того, чтобы методы DAO вызывались из уровня пользовательского интерфейса (или контроллеров). Кроме того, когда модульное тестирование уровня DAO, в частности, с аннотацией DAO, также гарантирует, что оно проверено на функциональность транзакций.
Ответ 8
Кроме того, Spring рекомендует использовать только аннотацию для конкретных классов, а не интерфейсов.
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Ответ 9
Как правило, на сервисный уровень следует поместить транзакцию.
Но, как указывалось ранее, атомарность операции - это то, что говорит нам о необходимости аннотации. Таким образом, если вы используете фреймворки, такие как Hibernate, где одна операция "сохранить/обновить/удалить/..." на объекте может изменить несколько строк в нескольких таблицах (из-за каскада через граф объектов), Конечно, также должно быть управление транзакциями по этому конкретному методу DAO.
Ответ 10
Для транзакции на уровне базы данных
в основном я использовал @Transactional
в DAO только на уровне метода, поэтому конфигурация может быть специально для метода/с использованием по умолчанию (требуется)
-
Метод DAO, который получает выборку данных (выберите...) - не нужен
@Transactional
Это может привести к некоторым накладным расходам из-за перехватчик транзакций/и прокси-сервер AOP, которые необходимо выполнить как хорошо. -
Методы DAO, которые вставляют/обновляют, получат
@Transactional
очень хороший блог на трансформальный
Для уровня приложения -
Я использую транзакцию для бизнес-логики, я хотел бы иметь возможность отката в случае непредвиденной ошибки
@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){
try {
//service logic here
} catch(Throwable e) {
log.error(e)
throw new MyApplicationException(..);
}
}
Ответ 11
Лучше иметь его в сервисном слое! Это ясно объясняется в одной из статей, которые я встретил вчера! Вот ссылка, которую вы можете проверить!
Ответ 12
@Transactional
Аннотации должны быть размещены вокруг всех операций, которые неотделимы.
Использование @Transactional
распространения транзакций обрабатывается автоматически. В этом случае, если другой метод вызывается текущим методом, тогда этот метод будет иметь возможность присоединить текущую транзакцию.
Итак, давайте возьмем пример:
У нас есть 2 модели, т.е. Country
и City
. Реляционное сопоставление моделей Country
и City
похоже на одно Country
может иметь несколько городов, так что отображение похоже на
@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;
Здесь Страна сопоставлена с несколькими городами с их выборкой Lazily
. Итак, вот роль @Transactinal
, когда мы извлекаем объект Country из базы данных, тогда мы получим все данные объекта Country, но не получим Set of cities, потому что мы выбираем города Lazily
.
//Without @Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//After getting Country Object connection between countryRepository and database is Closed
}
Когда мы хотим получить доступ к Set of Cities из объекта страны, тогда мы получим нулевые значения в этом Set, потому что объект Set, созданный только этим Set, не инициализируется с данными для получения значений Set, которые мы используем @Transactional
, т.е.
//with @Transactional
@Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
Object object = country.getCities().size();
}
Таким образом, в основном @Transactional
служба может выполнять множественный вызов в одной транзакции без закрытия соединения с конечной точкой.
Ответ 13
В идеале, уровень сервиса (менеджер) представляет вашу бизнес-логику и, следовательно, он должен быть аннотирован с помощью @Transactional
. Уровень сервиса может вызывать разные DAO для выполнения операций БД. Давайте рассмотрим ситуации, в которых у вас есть N число операций DAO в методе службы. Если ваша первая операция DAO не удалась, другие могут быть переданы, и вы закончите несогласованное состояние БД. Уровень аннотирования сервисов может спасти вас от таких ситуаций.
Ответ 14
Прежде всего, определим, где мы должны использовать транзакцию?
Я думаю, что правильный ответ - когда нам нужно убедиться, что последовательность действий будет завершена вместе как одна атомная операция или никаких изменений не будет сделано, даже если одно из действий не удастся.
Хорошо известно, что бизнес-логика вводится в сервисы. Таким образом, методы обслуживания могут содержать различные действия, которые должны выполняться как единая логическая единица работы. Если это так - тогда такой метод должен быть отмечен как Транзакционный. Конечно, не каждый метод требует такого ограничения, поэтому вам не нужно отмечать весь сервис как транзакционный.
И даже больше - не забудьте принять во внимание, что @Transactional, очевидно, может снизить производительность метода. Чтобы увидеть всю картину, вам нужно знать уровни изоляции транзакций. Знание этого может помочь вам избежать использования @Transactional, где это не обязательно.
Ответ 15
Я предпочитаю использовать @Transactional
на уровне сервиса на уровне метода.
Ответ 16
@Transactional
используется в слое службы, который вызывается с использованием уровня контроллера (@Controller
) и вызова уровня обслуживания на уровне DAO (@Repository
). Операция, связанная с базой данных.
Ответ 17
Сервисный уровень - лучшее место для добавления аннотаций @Transactional
в качестве основной части бизнес-логики, присутствующей здесь, и содержит поведение прецедента в уровне детализации.
Предположим, мы добавим его в DAO и из сервиса, который мы вызываем 2 класса DAO, один неудачный и другой успех, в этом случае, если @Transactional
не на службе одна БД будет фиксация, а другая будет отката.
Следовательно, моя рекомендация использует эту аннотацию мудро и используется только на уровне сервиса.
Ответ 18
@Transactional
следует использовать на уровне сервиса, так как он содержит бизнес-логику. Уровень DAO обычно имеет только операции CRUD базы данных.
// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
Spring doc: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html