Spring Transaction Management: использование @Transactional против использования AOP (<aop: advisor)
У меня путаница по поводу управления транзакциями Spring. В моем приложении я реализовал управление транзакциями, используя @Transactional в классе обслуживания. И я настроил свой spring.xml так:
<beans:bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">${jdbc.dialect}</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<!-- Transaction manager -->
<beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>
Если я реализую управление транзакциями в файле конфигурации, как показано ниже, без использования @Transactional в классе обслуживания:
<aop:pointcut id="defaultServiceOperation"
expression="execution(* x.y.service.*Service.*(..))"/>
<aop:pointcut id="noTxServiceOperation"
expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>
<aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>
<aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>
</aop:config>
это дает мне какие-то преимущества по сравнению с @Transactional? Кто-то сказал мне, что использование @Transactional также является реализацией AOP весной. Может кто-нибудь объяснить мне, как?
1 ответ
Не будет
Выгоды
Если вам не нужны какие-то очень конкретные требования или у вас нет проблем с производительностью, вам не следует изобретать велосипед. Spring - почти идеально разработанный, протестированный и заостренный инструмент, который можно заменить даже для серверов корпоративных приложений. @Transactional
это декларативный способ управления транзакциями, он гораздо удобнее и удобочитаемее, чем любые другие конфигурации XML. Его преимущества включают автоматическую обработку всех аспектов управления транзакциями декларативным способом: уровни изоляции и распространения (управлять вложенными транзакциями нелегко), тайм-ауты, условия отката и отдельные TransactionManager для каждого отдельного метода класса вашего сервиса. Легко читается, прост в настройке, прост в использовании.
@Transactional(readOnly = false, rollbackFor = ServiceException.class, isolation = Isolation.READ_COMMITTED)
public void myServiceJob(...)
Когда вы видите этот метод, легко понять его транзакционные атрибуты (без предоставления деталей реализации транзакций в методе). В случае простого AOP каждый раз, когда вы хотите узнать, что происходит в этом методе, вы должны проверить свою конфигурацию xml и найти соответствующий метод, который менее элегантен.
С другой стороны, очень трудно отлаживать или использовать эти прокси для любого другого декларативного управления. Например, это сложно (но не невозможно) извлечь ваш компонент из контекста и извлечь что-то из упакованного компонента, используя отражение (скажем, для целей мониторинга). Кроме того, когда bean-компонент вызывает один из его методов, он не будет делегирован прокси, потому что ваш bean-компонент ничего не знает о прокси, поэтому this
относится к самому бобу. Единственный способ вылечить это - предоставить поле "self" и установить его в постпроцессоре пользовательского компонента (но ваша реализация тоже страдает от этого).
Реализация
Если Spring настроен на использование управления транзакциями, он ищет @Transactional
аннотация на определения бина и создает автоматически сгенерированный прокси AOP, который является подклассом вашего бина. Поведение Spring прокси по умолчанию просто делегирует вызовы метода базовому компоненту. Затем Spring внедряет TransactionInterceptor с необходимыми TransactionManager. Код перехватчика выглядит довольно просто:
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
Внутри invokeWithinTransaction
TransactionInterceptor определяет, должен ли вызов выполняться в рамках транзакции вызывающей стороны (если она существует) или в новой (это касается уровня распространения). Затем он выбирает соответствующий TransactionManager, настраивает время ожидания и уровень изоляции, затем вызывает метод. После этого решается, должна ли транзакция быть зафиксирована или откатана (выбор делается на основе перехваченного исключения и времени).