У меня есть путаница в управлении транзакциями 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 - это также реализация АОП весной. Может ли кто-нибудь объяснить мне, как?
Это не так.
Выгоды
Если вам не нужны какие-то очень определенные требования или у вас нет проблем с производительностью, вы не должны изобретать велосипед. Весна практически идеально спроектирована, протестирована и скорректирована, что может быть заменой даже для серверов корпоративных приложений. @Transactional
является декларативным способом управления транзакциями, он гораздо удобнее и читабельнее любых конфигураций aop xml. К преимуществам относится автоматическая обработка всех аспектов управления транзакциями декларативным способом: уровни изоляции и распространения (нелегко контролировать вложенные транзакции), тайм-ауты, условия отката и различные транзакционные менеджеры для каждого отдельного метода вашего класса обслуживания. Легко читается, легко настраивается, прост в использовании.
@Transactional(readOnly = false, rollbackFor = ServiceException.class, isolation = Isolation.READ_COMMITTED)
public void myServiceJob(...)
Когда вы видите этот метод, легко понять его транзакционные атрибуты (без предоставления сведений о реализации транзакций в методе). В случае простого AOP каждый раз, когда вы хотите узнать, что происходит в этом методе, вы должны проверить свой xml-конфигуратор и найти соответствующий метод, который менее изящный.
С другой стороны, очень сложно отлаживать или использовать эти прокси для любого другого декларативного управления. Например, это сложно (но не невозможно) извлечь ваш компонент из контекста и получить что-то из вашего завернутого bean-компонента, используя отражение (скажем, для целей мониторинга). Кроме того, когда bean вызывает один из его методов, он не будет делегирован proxy, потому что ваш bean-компонент ничего не знает о прокси-сервере, поэтому this
относится к самому bean-компоненту. Единственный способ вылечить это, чтобы обеспечить "я" поле и установить его в пользовательском bean postprocessor (но ваша реализация также страдает от этого).
Реализация
Если Spring настроен на использование управления транзакциями, он ищет аннотацию @Transactional
для определений bean-компонентов и создает автоматически сгенерированный прокси AOP, который является подклассом вашего компонента. Поведение по умолчанию прокси-сервера Spring просто делегирует вызовы методов базовому компоненту. Затем Spring вводит TransactionInterceptor с необходимыми TransactionManagers. Код перехватчика выглядит довольно просто:
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 invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
Внутри invokeWithinTransaction
TransactionInterceptor определяет, должен ли быть вызов в области транзакции вызывающего абонента (если таковой существует) или в новой (это о уровне распространения). Затем он выбирает соответствующий TransactionManager, настраивает время ожидания и уровень изоляции, а затем вызывает метод. После того, как он решает, следует ли совершать транзакции или откатываться (выбор производится на основе исключенного и синхронизированного отслеживания).