使用注解 + AOP代理的方式对业务包方法的标记,配置继承AbstractRoutingDataSource类实现对于数据源的切换.
测试时, 可以进行查询,但不能进行更新插入等写数据库操作。
使用@order() 默认值为2147483647,对切换数据源的注解和开启事务注解进行标注, 测试失败。
应用启动时使用了@EnableTransactionManagement() 开启了事务管理。
用AOP切换数据源,AOP的切点必须在事务开启之前切换,否则无效,因为spring一旦使用事务获取连接,
则会在事务开启后获取到连接,后面的都是放入当前线程中,即事务内所用的连接都是同一个,此时是无法改变的,
必须要在事务开启前切换好数据源才能达到目的。
解决方法:编写事务配置类,配置事务管理器PlatformTransactionManager,定义相关业务接口和实现类新的事务传播行为。
(传播行为定义了被调用方法的事务边界) REQUIRES_NEW(),配置自定义的事务拦截器,将服务接口及实现类配置进去。
- PlatformTransactionManager
package org.springframework.transaction; import org.springframework.lang.Nullable; public interface PlatformTransactionManager { //事务状态 TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException; //提交事务 void commit(TransactionStatus var1) throws TransactionException; //回滚事务 void rollback(TransactionStatus var1) throws TransactionException; }
- 配置事务管理器
@Bean(CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME)
public TransactionInterceptor customizeTransactionInterceptor(PlatformTransactionManager transactionManager) {
NameMatchTransactionAttributeSource transactionAttributeSource = new NameMatchTransactionAttributeSource();
RuleBasedTransactionAttribute readOnly = this.readOnlyTransactionRule();
RuleBasedTransactionAttribute required = this.requiredTransactionRule();
// 默认的只读事务配置
for (String methodName : DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES) {
transactionAttributeSource.addTransactionalMethod(methodName, readOnly);
}
// 默认的传播事务配置
for (String methodName : DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES) {
transactionAttributeSource.addTransactionalMethod(methodName, required);
}
// 定制的只读事务配置
for (String methodName : customizeReadOnlyMethodRuleTransactionAttributes) {
transactionAttributeSource.addTransactionalMethod(methodName, readOnly);
}
// 定制的传播事务配置
for (String methodName : customizeRequiredMethodRuleTransactionAttributes) {
transactionAttributeSource.addTransactionalMethod(methodName, required);
}
return new TransactionInterceptor(transactionManager, transactionAttributeSource);
}
- 配置拦截器
@Bean
public BeanNameAutoProxyCreator customizeTransactionBeanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
// 设置定制的事务拦截器
beanNameAutoProxyCreator.setInterceptorNames(CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME);
// 默认
for ( String defaultTransactionBeanNameSuffix : DEFAULT_TRANSACTION_BEAN_NAMES ) {
beanNameAutoProxyCreator.setBeanNames( defaultTransactionBeanNameSuffix );
}
// 定制
for (String customizeTransactionBeanName : customizeTransactionBeanNames) {
beanNameAutoProxyCreator.setBeanNames(customizeTransactionBeanName);
}
beanNameAutoProxyCreator.setProxyTargetClass(true);
return beanNameAutoProxyCreator;
}
- 传播行为
( 传播行为定义了被调用方法的事务边界 )
传播行为 propagation | 意义 |
PROPAGATION_REQUIRED | 方法必须运行在一个事务内,如果当前存在一个事务,那么该方法运行在这个事务中,否则,将创建一个新的事务。 |
REQUIRES_NEW | 创建一个新的事务,如果存在当前事务的话,暂停(挂起)当前事务 。 |
SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
NOT_SUPPORTED | 不执行当前事务;总是执行非事务。 |
MANDATORY | 支持当前事务;如果当前事务不存在则抛出一个异常。 |
NESTED | 如果当前存在事务的话,执行一个嵌套的事务,不存在创建新的。 |
NEVER | 不支持当前事务;如果存在当前事务则抛出一个异常 |