SpringBoot + Mybatis 多数据源切换无法进行 写数据库 操作记录

  使用注解 + 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 不支持当前事务;如果存在当前事务则抛出一个异常



  
posted @ 2019-11-14 17:18  爪哇搬砖  阅读(...)  评论(... 编辑 收藏