springboot2.x+mybatis plus整合多數據源

springboot2.x+mybatis plus整合多數據源

mybatisplus手動多數據源配置切換

一、springboot2.x+mybatis plus整合多數據源

1.1 數據庫

oa庫
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
  `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  `password` varchar(500) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  `name` varchar(25) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '姓名',
  `sex` char(1) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '1' COMMENT '0:女',
  `status` char(1) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '1' COMMENT '用戶的屬性 1-編制 2-兼職',
  PRIMARY KEY (`id`) USING BTREE,
) 
cdt庫
DROP TABLE IF EXISTS `cdt_user`;
CREATE TABLE `cdt_user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用戶id',
  `pwd` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `nickName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '暱稱',
  `sex` int(1) DEFAULT 0 COMMENT '0代表女  1代表男',
  `countryCode` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '86-中國 ; 0081 - 日本 ',
  `mobile` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '電話號碼',
  `headPic` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '頭像',
  `age` int(11) DEFAULT 18 COMMENT '年齡',
) 

1.2 生成映射文件

MybatisplusUtil.java映射文件生成工具生成映射文件

package com.hanergy.out.utils;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 數據庫生成JAVA類
 */
public class MybatisPlusUtils {

    public static String[] getAllTables() {
        List<String> list = new ArrayList<>();
        try {
            Connection connection = DriverManager.getConnection("jdbc:mysql://rm-e.mysql.rds.aliyuncs.com:3306/cdt?useSSL=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull", "root", "xxxx");
            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet tables = metaData.getTables(null, null, null, new String[]{"TABLE"});
            while (tables.next()) {
                list.add(tables.getString(3));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list.toArray(new String[]{});
    }

    /**
     * 自動代碼生成類
     *
     * @param includeTables
     * @param excludeTables
     */
    public static void generateMysql(String[] includeTables, String[] excludeTables, Boolean db1) {
        AutoGenerator autoGenerator = new AutoGenerator();
        /**
         * 數據庫配置
         */

        buildDb(autoGenerator);
        /**
         * 數據庫表配置
         */
        StrategyConfig strategyConfig = new StrategyConfig();
        // 駝峯命名
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        // 需要生成的表名
//        includeTables = new String[]{"user"};
        // 不需要生成的表名
//        excludeTables = new String[]{};
        strategyConfig.setInclude(includeTables);
        strategyConfig.setExclude(excludeTables);
        strategyConfig.setTablePrefix("");
        autoGenerator.setStrategy(strategyConfig);

        /**
         * 全局配置
         */
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setAuthor("Du Ronghong");
        globalConfig.setDateType(DateType.ONLY_DATE);
        globalConfig.setActiveRecord(true);
        globalConfig.setIdType(IdType.INPUT);
        globalConfig.setOutputDir("D:/test/video");
        globalConfig.setMapperName("%sMapper");
        globalConfig.setServiceName("I%sService");
        globalConfig.setServiceImplName("%sServiceImpl");
        globalConfig.setXmlName("%sMapper");
        //globalConfig.setSwagger2(true);
        globalConfig.setFileOverride(true);
        globalConfig.setBaseColumnList(false);
        globalConfig.setBaseResultMap(false);
        globalConfig.setEnableCache(false);
        autoGenerator.setGlobalConfig(globalConfig);

        /**
         * 包名配置
         */
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent("");
        packageConfig.setEntity("com.hanergy.out.entity");
        packageConfig.setMapper("com.hanergy.out.dao");
        packageConfig.setXml("mapper");
        packageConfig.setService("com.hanergy.out.service");
        packageConfig.setServiceImpl("com.hanergy.out.service.impl");
        packageConfig.setController("com.hanergy.out.controller");


        autoGenerator.setPackageInfo(packageConfig);
        // 採用默認模板,自定義模板參考@see com.baomidou.mybatisplus.generator.config.TemplateConfig
//        TemplateConfig templateConfig = new TemplateConfig();
        autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
        autoGenerator.execute();
    }


    private static void buildDb(AutoGenerator autoGenerator) {
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDbType(DbType.MYSQL);
        dataSourceConfig.setDriverName("com.mysql.jdbc.Driver");
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("xxxx");
        dataSourceConfig.setUrl("jdbc:mysql://rmo.mysql.rds.aliyuncs.com:3306/cdt?useSSL=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull");
        autoGenerator.setDataSource(dataSourceConfig);
    }
    //com.hanergy.modules.activiti.entity
    public static void main(String[] args) {
        //要生成映射的表名
        String[] includeTables = {"hr_kpi_dept_person","sys_user"};
        generateMysql(includeTables,null,false);
    }
}

1.3 項目結構

在這裏插入圖片描述

二、多數據源配置

2.1 pom.xml

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>
		<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.0-gamma</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
                <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
               <!--引入AOP依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.1.6.RELEASE</version>
        </dependency>

2.2 填寫配置信息

application.yml配置mybatisplus以及多數據源

spring:
  aop:
    auto: true
    proxy-target-class: true
  datasource:
    druid:
      #oa
      oa:
        url: jdbc:mysql://rm-2zezdhr94r3t4et671o.mysql.rds.aliyuncs.com:3306/oa?useSSL=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
        username: root
        password: ArA8IyYFmQcrlxJP
        driver-class-name: com.mysql.jdbc.Driver
        initialSize: 5
        minIdle: 5
        maxActive: 20
        #cdt
      cdt:
        url: jdbc:mysql://rm-2zezdhr94r3t4et671o.mysql.rds.aliyuncs.com:3306/cdt?useSSL=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
        username: root
        password: ArA8IyYFmQcrlxJP
        driver-class-name: com.mysql.jdbc.Driver
        initialSize: 5
        minIdle: 5
        maxActive: 20
        
#mybatis
mybatis-plus:
  mapper-locations: classpath:mybatis/*.xml
  #實體掃描,多個package用逗號或者分號分隔
  typeAliasesPackage: com.hanergy.out.*.entity
  global-config:
    #自定義SQL注入器
    db-config:
      #主鍵類型  0:"數據庫ID自增", 1:"用戶輸入ID",2:"全局唯一ID (數字類型唯一ID)", 3:"全局唯一ID UUID";
      id-type: input
      #字段策略 0:"忽略判斷",1:"非 NULL 判斷"),2:"非空判斷"
      field-strategy: NOT_NULL
      #邏輯刪除配置
      logic-delete-value: -1
      logic-not-delete-value: 0
    #刷新mapper 調試神器
    refresh: true

2.3 數據源配置

package com.hanergy.out.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
//import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author : hld
 * @date : 2017/9/6
 */
@Configuration
public class DataSourceConfig {

    /**
     * 動態數據源配置
     *
     * @param dataSourceOrder : 訂單數據源
     * @param dataSourceUser  : 用戶數據源
     * @return
     */
    @Bean
    public DynamicMultipleDataSource multipleDataSource ( @Qualifier( GlobalConstant.OA_DATA_SOURCE_KEY ) DataSource dataSourceOrder ,
                                                          @Qualifier( GlobalConstant.CDT_DATA_SOURCE_KEY ) DataSource dataSourceUser ) {
        DynamicMultipleDataSource dynamicMultipleDataSource = new DynamicMultipleDataSource();
        Map< Object, Object >     targetDataSources         = new HashMap<>();
        targetDataSources.put( GlobalConstant.OA_DATA_SOURCE_KEY , dataSourceOrder );
        targetDataSources.put( GlobalConstant.CDT_DATA_SOURCE_KEY , dataSourceUser );
        dynamicMultipleDataSource.setTargetDataSources( targetDataSources );
        dynamicMultipleDataSource.setDefaultTargetDataSource( dataSourceOrder );
        return dynamicMultipleDataSource;
    }

    @Primary
    @Bean
    @ConfigurationProperties( prefix = "spring.datasource.druid.oa" )
    public DataSource oa () {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties( prefix = "spring.datasource.druid.cdt" )
    public DataSource cdt () {
        return DruidDataSourceBuilder.create().build();
    }


    @Bean
    public SqlSessionFactory sqlSessionFactory (DynamicMultipleDataSource dynamicMultipleDataSource ) throws
                                                                                                       Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource( dynamicMultipleDataSource );
        return sqlSessionFactoryBean.getObject();
    }

    @Bean
    public DataSourceTransactionManager transactionManager (DynamicMultipleDataSource dynamicMultipleDataSource ) throws
                                                                                                                   Exception {
        return new DataSourceTransactionManager( dynamicMultipleDataSource );
    }

    @Bean
    @Primary
    public MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean (DynamicMultipleDataSource dynamicMultipleDataSource ) {
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource( dynamicMultipleDataSource );
         PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        // 不加上這句話多數據源配置 mybatisplus正常  但是讀取.xml  sql會報錯找不到方法。
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mybatis/*.xml"));
        return sqlSessionFactoryBean;
    }
}

package com.hanergy.out.config;

import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 動態數據源註解
 * {@link DataSourceSwitch}
 *
 * @author : hld
 * @date : 2017/9/6
 */
@Retention( RetentionPolicy.RUNTIME )
@Target( { ElementType.METHOD , ElementType.TYPE } )
public @interface DynamicDataSource {

    @AliasFor( "dataSource" )
    String value() default StringUtils.EMPTY;

    @AliasFor( "value" )
    String dataSource() default StringUtils.EMPTY;
}
package com.hanergy.out.config;

/**
 * 全局常量
 *
 * @author : hld
 * @date : 2017/9/7
 */
public abstract class GlobalConstant {

    /** 多數據源key : 訂單系統數據源 **/
    public static final String OA_DATA_SOURCE_KEY = "oa";
    /** 多數據源key : 用戶系統數據源 **/
    public static final String CDT_DATA_SOURCE_KEY  = "cdt";

}
package com.hanergy.out.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author : hld
 * @date : 2017/5/10
 * mybatis:xml文件路徑
 */
@Configuration
@MapperScan( {
        "mybatis",
} )
public class MybatisPlusConfig {

    /**
     * 分頁插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

    /**
     * mybatis-plus 性能分析攔截器<br>
     * 文檔:http://mp.baomidou.com<br>
     */
    @Bean
    public PerformanceInterceptor performanceInterceptor () {
        return new PerformanceInterceptor();
    }
}

package com.hanergy.out.config;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author : hld
 */
public class DataSourceSwitchMethodInterceptor implements MethodInterceptor {

    @Override
    public Object invoke ( MethodInvocation invocation ) throws Throwable {
        final String packageName = invocation.getThis().getClass().getPackage().getName();
        if ( packageName.contains( "cdt" ) ) {
            setDataSourceKey( invocation.getMethod() , GlobalConstant.CDT_DATA_SOURCE_KEY );
        }
        if ( packageName.contains( "oa" ) ) {
            setDataSourceKey( invocation.getMethod() , GlobalConstant.OA_DATA_SOURCE_KEY );
        }
        return invocation.proceed();
    }


    /**
     * 設置數據源key
     */
    private void setDataSourceKey ( final Method method , final String defaultKey ) {
        final DynamicDataSource dynamicDataSource = method.getAnnotation( DynamicDataSource.class );
        if ( Objects.isNull( dynamicDataSource ) ) {
            DynamicMultipleDataSource.setDataSourceKey( defaultKey );
            return;
        }
        DynamicMultipleDataSource.setDataSourceKey( dynamicDataSource.value() );
    }


}

2.4 利用AOP進行數據源的動態切換

package com.hanergy.out.config;

import com.hanergy.out.Interceptor.LoginInterceptor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author : hld
 * @date : 2017/9/6
 */
@Aspect
@Order( -100 )		//數值越小 越優先執行
@Component
public class DataSourceSwitch {

    Logger log = LoggerFactory.getLogger(DataSourceSwitch.class);

    @Before( "execution(* com.hanergy.out.service.oa..*.*(..))" )
    public void dataPlatform ( JoinPoint joinPoint ) {
        log.info("切換數據源oa");
        setDataSourceKey( joinPoint , GlobalConstant.OA_DATA_SOURCE_KEY );
    }

    @Before( "execution(* com.hanergy.out.service.cdt..*.*(..))" )
    public void shop ( JoinPoint joinPoint ) {
        log.info("切換數據源cdt");
        setDataSourceKey( joinPoint , GlobalConstant.CDT_DATA_SOURCE_KEY );
    }

    /**
     * 設置數據源key
     */
    private void setDataSourceKey (JoinPoint joinPoint , final String defaultKey ) {
        final Method            method            = this.currentMethod( joinPoint );
        final DynamicDataSource dynamicDataSource = method.getAnnotation( DynamicDataSource.class );
        if ( Objects.isNull( dynamicDataSource ) ) {
            DynamicMultipleDataSource.setDataSourceKey( defaultKey );
            return;
        }
        DynamicMultipleDataSource.setDataSourceKey( dynamicDataSource.value() );
    }


    /**
     * 獲取當前執行的方法
     */
    private Method currentMethod ( JoinPoint joinPoint ) {
        return ( (MethodSignature) joinPoint.getSignature() ).getMethod();
    }
}

package com.hanergy.out.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 動態數據源路由
 *
 * @author : hld
 * @date : 2017/9/6
 */
public class DynamicMultipleDataSource extends AbstractRoutingDataSource {

    private static final ThreadLocal< String > DATA_SOURCE_KEY = new ThreadLocal<>();

    static void setDataSourceKey ( String dataSource ) {
        DATA_SOURCE_KEY.set( dataSource );
    }

    private static void clear () {
        DATA_SOURCE_KEY.remove();
    }

    @Override
    protected Object determineCurrentLookupKey () {
        final String lookupKey = DATA_SOURCE_KEY.get();
        clear();
        return lookupKey;
    }


}

2.5 多數據源事務

package com.hanergy.out.config;


import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @author : 披荊斬棘
 * @date : 2017/9/8
 */
@Configuration
@ConfigurationProperties( prefix = "transactional" )
public class TransactionalConfig {

    private static final String   CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME               = "customizeTransactionInterceptor";
    private static final String   DATA_SOURCE_SWITCH_METHOD_INTERCEPTOR_NAME           = "dataSourceSwitchMethodInterceptor";
    /**
     * 默認只對 "*Service" , "*ServiceImpl" Bean 進行事務處理,"*"表示模糊匹配, 比如 : userService,orderServiceImpl
     */
    private static final String[] DEFAULT_TRANSACTION_BEAN_NAMES                       = { "*Service" , "*ServiceImpl" };
    /**
     * 可傳播事務配置
     */
    private static final String[] DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES  = {
            "add*" ,
            "save*" ,
            "insert*" ,
            "delete*" ,
            "update*" ,
            "edit*" ,
            "batch*" ,
            "create*" ,
            "remove*" ,
    };
    /**
     * 默認的只讀事務
     */
    private static final String[] DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES = {
            "get*" ,
            "count*" ,
            "find*" ,
            "query*" ,
            "select*" ,
            "list*" ,
            "*" ,
    };
    /**
     * 自定義事務 BeanName 攔截
     */
    private              String[] customizeTransactionBeanNames                        = {};
    /**
     * 自定義方法名的事務屬性相關聯,可以使用通配符(*)字符關聯相同的事務屬性的設置方法; 只讀事務
     */
    private              String[] customizeReadOnlyMethodRuleTransactionAttributes     = {};
    /**
     * 自定義方法名的事務屬性相關聯,可以使用通配符(*)字符關聯相同的事務屬性的設置方法;
     * 傳播事務(默認的){@link org.springframework.transaction.annotation.Propagation#REQUIRED}
     */
    private              String[] customizeRequiredMethodRuleTransactionAttributes     = {};


    /**
     * 配置事務攔截器
     *
     * @param transactionManager : 事務管理器
     * @return
     */
    @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 );
    }


    /**
     * 配置事務 AOP 切入點
     * {@link DataSourceSwitch}
     *
     * @param transactionInterceptor : {@link #customizeTransactionInterceptor(PlatformTransactionManager)}

     @Bean public AspectJExpressionPointcutAdvisor aspectJExpressionPointcutAdvisor ( @Qualifier( "customizeTransactionInterceptor" ) TransactionInterceptor transactionInterceptor ) {
     AspectJExpressionPointcutAdvisor pointcut = new AspectJExpressionPointcutAdvisor();
     pointcut.setAdvice( transactionInterceptor );
     pointcut.setExpression( "execution (* com.aidijing.*.*service.*.*(..))" );
     return pointcut;
     }
     */


    /**
     * {@link #dataSourceSwitchMethodInterceptor()}
     * {@link #customizeTransactionInterceptor(PlatformTransactionManager)}
     *
     * @return
     */
    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator () {
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setInterceptorNames( DATA_SOURCE_SWITCH_METHOD_INTERCEPTOR_NAME ,
                                                      CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME );

        List< String > transactionBeanNames = new ArrayList<>( DEFAULT_TRANSACTION_BEAN_NAMES.length + customizeTransactionBeanNames.length );
        // 默認
        transactionBeanNames.addAll( Arrays.asList( DEFAULT_TRANSACTION_BEAN_NAMES ) );
        // 定製
        transactionBeanNames.addAll( Arrays.asList( customizeTransactionBeanNames ) );
        // 歸集
        for ( String transactionBeanName : transactionBeanNames ) {
            beanNameAutoProxyCreator.setBeanNames( transactionBeanName );
        }
        beanNameAutoProxyCreator.setProxyTargetClass( true );
        return beanNameAutoProxyCreator;
    }

    @Bean( DATA_SOURCE_SWITCH_METHOD_INTERCEPTOR_NAME )
    public DataSourceSwitchMethodInterceptor dataSourceSwitchMethodInterceptor () {
        return new DataSourceSwitchMethodInterceptor();
    }


    /**
     * 支持當前事務;如果不存在創建一個新的
     */
    private RuleBasedTransactionAttribute requiredTransactionRule () {
        RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute();
        required.setRollbackRules( Collections.singletonList( new RollbackRuleAttribute( Exception.class ) ) );
        required.setPropagationBehavior( TransactionDefinition.PROPAGATION_REQUIRED );
        required.setTimeout( TransactionDefinition.TIMEOUT_DEFAULT );
        return required;
    }

    /**
     * 只讀事務
     */
    private RuleBasedTransactionAttribute readOnlyTransactionRule () {
        RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute();
        readOnly.setReadOnly( true );
        readOnly.setPropagationBehavior( TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
        return readOnly;
    }


    public static String getCustomizeTransactionInterceptorName() {
        return CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME;
    }

    public static String getDataSourceSwitchMethodInterceptorName() {
        return DATA_SOURCE_SWITCH_METHOD_INTERCEPTOR_NAME;
    }

    public static String[] getDefaultTransactionBeanNames() {
        return DEFAULT_TRANSACTION_BEAN_NAMES;
    }

    public static String[] getDefaultRequiredMethodRuleTransactionAttributes() {
        return DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES;
    }

    public static String[] getDefaultReadOnlyMethodRuleTransactionAttributes() {
        return DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES;
    }

    public String[] getCustomizeTransactionBeanNames() {
        return customizeTransactionBeanNames;
    }

    public void setCustomizeTransactionBeanNames(String[] customizeTransactionBeanNames) {
        this.customizeTransactionBeanNames = customizeTransactionBeanNames;
    }

    public String[] getCustomizeReadOnlyMethodRuleTransactionAttributes() {
        return customizeReadOnlyMethodRuleTransactionAttributes;
    }

    public void setCustomizeReadOnlyMethodRuleTransactionAttributes(String[] customizeReadOnlyMethodRuleTransactionAttributes) {
        this.customizeReadOnlyMethodRuleTransactionAttributes = customizeReadOnlyMethodRuleTransactionAttributes;
    }

    public String[] getCustomizeRequiredMethodRuleTransactionAttributes() {
        return customizeRequiredMethodRuleTransactionAttributes;
    }

    public void setCustomizeRequiredMethodRuleTransactionAttributes(String[] customizeRequiredMethodRuleTransactionAttributes) {
        this.customizeRequiredMethodRuleTransactionAttributes = customizeRequiredMethodRuleTransactionAttributes;
    }
}

三、測試

controller添加@Transactional事務註解

    @ApiOperation(value="根據訂單號獲取訂單信息",notes="根據訂單號獲取訂單信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name="historyId",value="訂單號",required=true,paramType="query")
    })
    @GetMapping("/order")
    public R findHistoryInfo(@RequestParam("historyId")Integer historyId) {
        log.info(historyId.toString());
        //cdt庫查詢數據
        CdtCheckHistory cdtCheckHistory = cdtCheckHistoryService.findByHistoryId(historyId);
        SysUser sysUser = new SysUser();
        sysUser.setEmail("11111");
        sysUser.setName("111111");
        sysUser.setUsername("111111");
        sysUser.setImage("111111");
        // oa庫
        sysUserService.insert(sysUser);
        // cdt庫
        CdtCheckHistory cdtCheckHistory1 = cdtCheckHistoryService.findByHistoryId(historyId);
        // 事務測試
        int i = 1/0;
        return R.ok(200,cdtCheckHistory);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章