1、在application.properties中添加数据库连接配置

mybatis.type-aliases-package=com.yc.edusys.bean
     mybatis.mapper-locations=classpath:mapper/*Mapper.xml
     
     # 第一个数据源
     jdbc1.driverClassName = com.mysql.jdbc.Driver
     jdbc1.url = jdbc:mysql://127.0.0.1:3306/edusys?useUnicode=true&characterEncoding=utf-8
     jdbc1.username = root
     jdbc1.password = a
     
     # 第二个数据源
     jdbc2.driverClassName = com.mysql.jdbc.Driver
     jdbc2.url = jdbc:mysql://127.0.0.1:3306/usersys?useUnicode=true&characterEncoding=utf-8
     jdbc2.username = root
     jdbc2.password = a

    2、创建一个枚举类 DatabaseType列出所有数据源的数据库名称

public enum DatabaseType {
     edusys,usersys
 }

3、DynamicDataSource继承AbstractRoutingDataSource并重写其中的方法determineCurrentLookupKey()

/**
  * 使用DatabaseContextHolder获取当前线程的DatabaseType
  * 动态数据源,需要继承AbstractRoutingDataSource
  * @author navy
  * @company 源辰信息
  */
 public class DynamicDataSource extends AbstractRoutingDataSource {
     private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<DataSourceType>();    public static void setDatabaseType(DataSourceType type){
         contextHolder.set(type);
     }    protected Object determineCurrentLookupKey() {  // determine: 决定、限定  CurrentLookupKey : 当前查找关键字
         return contextHolder.get();
     }
     
     public static void resetDataSourceType(){
         contextHolder.set(DataSourceType.edusys);
     }
 }

4、MyBatisConfig中生成2个数据源DataSource的bean与value

/**
  * springboot集成mybatis的基本入口 
  * 1、创建数据源(如果采用的是默认的tomcat-jdbc数据源,则不需要)
  * 2、创建SqlSessionFactory 
  * 3、配置事务管理器,除非需要使用事务,否则不用配置
  * 
  * 通过读取application.properties文件生成两个数据源(eduSysDataSource、userSysDataSource)
  * 使用以上生成的两个数据源构造动态数据源dataSource
  * @Primary:指定在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@Autowire注解报错(一般用于多数据源的情况下)
  * @Qualifier:指定名称的注入,当一个接口有多个实现类的时候使用(在本例中,有两个DataSource类型的实例,需要指定名称注入)
  * @Bean:生成的bean实例的名称是方法名(例如上边的@Qualifier注解中使用的名称是前边两个数据源的方法名,而这两个数据源也是使用@Bean注解进行注入的
  * 通过动态数据源构造SqlSessionFactory和事务管理器(如果不需要事务,后者可以去掉)
  */
 @Configuration // 该注解类似于spring配置文件
 // 指定需要扫描的包(mapper.xml文件存放的包路径)
 // @MapperScan(basePackages = "mapper")
 public class MyBatisConfig {
     @Autowired
     private Environment env;    /**
      * 创建数据源(数据源的名称:方法名可以取为XXXDataSource(),XXX为数据库名称,该名称也就是数据源的名称)
      * 
      * @Bean: 方法级别上的注解,相当于
      * <beans>
      *         <bean id="方法名" class="此方法返回的对象"/>
      * </beans>
      */
     @Bean
     public DataSource eduSysDataSource() throws Exception {
         Properties props = new Properties();
         props.put("driverClassName", env.getProperty("jdbc1.driverClassName"));
         props.put("url", env.getProperty("jdbc1.url"));
         props.put("username", env.getProperty("jdbc1.username"));
         props.put("password", env.getProperty("jdbc1.password"));
         return DruidDataSourceFactory.createDataSource(props);
     }    @Bean
     public DataSource userSysDataSource() throws Exception {
         Properties props = new Properties();
         props.put("driverClassName", env.getProperty("jdbc2.driverClassName"));
         props.put("url", env.getProperty("jdbc2.url"));
         props.put("username", env.getProperty("jdbc2.username"));
         props.put("password", env.getProperty("jdbc2.password"));
         return DruidDataSourceFactory.createDataSource(props);
     }  
     @Bean
     @Primary
     public DynamicDataSource dataSource(@Qualifier("eduSysDataSource") DataSource eduSysDataSource, @Qualifier("userSysDataSource") DataSource userSysDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
         targetDataSources.put(DataSourceType.edusys, eduSysDataSource);
         targetDataSources.put(DataSourceType.usersys, userSysDataSource);        DynamicDataSource dataSource = new DynamicDataSource();
         dataSource.setTargetDataSources(targetDataSources); // 该方法是AbstractRoutingDataSource的方法
         dataSource.setDefaultTargetDataSource(eduSysDataSource);// 默认的datasource设置为eduSysDataSource
         return dataSource;
     }    /**
      * 根据数据源创建SqlSessionFactory
      */
     @Bean
     public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception {
         SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
         sessionFactoryBean.setDataSource(ds); // 指定数据源(这个必须有,否则报错)
         
         // 下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则可以不加
         sessionFactoryBean.setTypeAliasesPackage(env.getProperty("mybatis.type-aliases-package"));// 指定基包
         sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapper-locations")));
         return sessionFactoryBean.getObject();
     }    /**
      * 配置事务管理器
      */
     @Bean
     public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
         return new DataSourceTransactionManager(dataSource);
     }
 }

5、将DynamicDataSource作为数据源注入到SqlSessionFactory的dataSource属性中去,并且该dataSource作为transactionManager的入参来构造DataSour

ceTransactionManager
 /**
  * 使用DatabaseContextHolder获取当前线程的DatabaseType
  * 动态数据源,需要继承AbstractRoutingDataSource
  * @author navy
  * @company 源辰信息
  */
 public class DynamicDataSource extends AbstractRoutingDataSource {
     private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<DataSourceType>();    public static void setDatabaseType(DataSourceType type){
         contextHolder.set(type);
     }    protected Object determineCurrentLookupKey() {  // determine: 决定、限定  CurrentLookupKey : 当前查找关键字
         return contextHolder.get();
     }
     
     public static void resetDataSourceType(){
         contextHolder.set(DataSourceType.edusys);
     }
 }

6、定义一个指定数据源的注解

/**
  * 数据源类型注解
  * @author navy
  * @company 源辰信息
  */
 @Retention(RetentionPolicy.RUNTIME) // 在运行时可见
 @Target(ElementType.METHOD) // 注解可以用在方法上
 public @interface DataSourceTypeAnnotation {
     DataSourceType value() default DataSourceType.edusys;
 }7、创建一个切面,用来切换数据源
 /**
  * 切换数据源的切面
  * @author navy
  * @company 源辰信息
  */
 @Component
 @Aspect
 @Order(-10)  // 让它在事务注解前面起作用
 public class DataSourceAspect {
     /**
      * 第一个*表示返回值类型
      * 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.yc.edusys.dao包、子孙包下所有类的方法
      * 第二个*号:表示类名,*号表示所有的类
      * *(..) : 最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
      */
     //@Pointcut("execution(* com.yc.edusys.dao..*.*(..)) && @annotation(com.yc.edusys.annotation.DataSourceTypeAnnotation)")
     //@Pointcut("execution(* com.yc.edusys.biz.impl.*.*(..)) && @annotation(com.yc.edusys.annotation.DataSourceTypeAnnotation)")
     @Pointcut("execution(* com.yc.edusys.biz.impl.*.*(..))")
     public void dataSourcePointcut() {
     }
  
     @Before("dataSourcePointcut()")
     public void doBefore(JoinPoint joinPoint) {
         MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
         Method method = methodSignature.getMethod();
         
         DataSourceTypeAnnotation typeAnnotation = method.getAnnotation(DataSourceTypeAnnotation.class);
         if (typeAnnotation == null) { // 如果没有这个注解,则默认访问edusys数据库
             DynamicDataSource.setDatabaseType(DataSourceType.edusys);
             return;
         }
         
         DataSourceType sourceType = typeAnnotation.value();
         if (sourceType == DataSourceType.usersys) {
             DynamicDataSource.setDatabaseType(DataSourceType.usersys);
         }else {
             DynamicDataSource.setDatabaseType(DataSourceType.edusys);
         }
     }
 }

8、在对应的方法上使用注解切换数据库

@DataSourceTypeAnnotation(DataSourceType.usersys)
 public int add(RoleInfo rf) {
     if (rf == null || StringUtil.isNull(rf.getRname())) {
         return -1;
     }
     return baseDao.update(RoleInfo.class, "addRole", rf);
 }