­

Springboot 整合Mybatis多数据源并动态切换

  • 2019 年 11 月 6 日
  • 筆記

作者:hy_xiaobin

来源:https://juejin.im/post/5d8705e65188253f4b629f47

首先需要建立两个库进行测试,我这里使用的是master_test和slave_test两个库,两张库都有一张同样的表(偷懒),表名 t_user

字段名

类型

备注

id

int

主键自增ID

name

varchar

名称

表中分别添加两条不同数据,方便测试 主数据库记录name为xiaobin,从库为xiaoliu。

目录结构

开始使用Springboot 整合mybatis,首先引入pom文件。

   <?xml version="1.0" encoding="UTF-8"?>  <project xmlns="http://maven.apache.org/POM/4.0.0"          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">     <modelVersion>4.0.0</modelVersion>     <parent>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-parent</artifactId>         <version>2.1.4.RELEASE</version>     </parent>     <groupId>com.xiaobin</groupId>     <artifactId>mysql_master_slave</artifactId>     <version>1.0-SNAPSHOT</version>       <properties>         <java.version>1.8</java.version>         <lombok.version>1.18.6</lombok.version>         <mybatis.version>1.3.2</mybatis.version>         <lombox.version>1.18.6</lombox.version>     </properties>       <dependencies>         <!-- 添加web启动坐标 -->         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>         <!-- 添加lombok工具坐标 -->         <dependency>             <groupId>org.projectlombok</groupId>             <artifactId>lombok</artifactId>             <version>${lombok.version}</version>         </dependency>         <!-- 添加springboot 测试坐标 -->         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-test</artifactId>         </dependency>         <!-- 添加lombox 测试坐标 -->         <dependency>             <groupId>org.projectlombok</groupId>             <artifactId>lombok</artifactId>             <version>${lombox.version}</version>         </dependency>         <!-- 添加mybatis依赖坐标 -->         <dependency>             <groupId>org.mybatis.spring.boot</groupId>             <artifactId>mybatis-spring-boot-starter</artifactId>             <version>${mybatis.version}</version>         </dependency>         <!-- 添加mysql驱动器坐标 -->         <dependency>             <groupId>mysql</groupId>             <artifactId>mysql-connector-java</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-jdbc</artifactId>         </dependency>         <!-- 添加druid数据源坐标 -->         <dependency>             <groupId>com.alibaba</groupId>             <artifactId>druid-spring-boot-starter</artifactId>             <version>1.1.10</version>         </dependency>         <!-- 添加AOP坐标 -->         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-aop</artifactId>         </dependency>       </dependencies>  </project>

动态数据源配置

这里使用的数据源为druid,实现数据源之间的切换用@DataSource自定义注解,配置Aop进行切换 application.yml 配置文件。

spring:      datasource:          type: com.alibaba.druid.pool.DruidDataSource          druid:            xiaobin-master: # 主数据源              driverClassName: com.mysql.jdbc.Driver              username: root              password: root              url: jdbc:mysql://localhost:3306/master_test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8            xiaobin-slave: # 从数据源              driverClassName: com.mysql.jdbc.Driver              username: root              password: root              url: jdbc:mysql://localhost:3306/slave_test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8  mybatis:   mapper-locations: classpath:mapper/*.xml

多数据源配置类

@Configuration  @Component  public class DynamicDataSourceConfig {        @Bean      @ConfigurationProperties("spring.datasource.druid.xiaobin-master")      public DataSource  xiaobinMasterDataSource(){          return DruidDataSourceBuilder.create().build();      }        @Bean      @ConfigurationProperties("spring.datasource.druid.xiaobin-slave")      public DataSource  xiaobinSlaveDataSource(){          return DruidDataSourceBuilder.create().build();      }        @Bean      @Primary      public DynamicDataSource dataSource(DataSource xiaobinMasterDataSource, DataSource xiaobinSlaveDataSource) {          Map<Object, Object> targetDataSources = new HashMap<>();          targetDataSources.put("xiaobin-master",xiaobinMasterDataSource);          targetDataSources.put("xiaobin-slave", xiaobinSlaveDataSource);          return new DynamicDataSource(xiaobinMasterDataSource, targetDataSources);      }  }

动态数据源切换类

public class DynamicDataSource  extends AbstractRoutingDataSource {        private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();        public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {          super.setDefaultTargetDataSource(defaultTargetDataSource);          super.setTargetDataSources(targetDataSources);          super.afterPropertiesSet();      }        @Override      protected Object determineCurrentLookupKey() {          return getDataSource();      }        public static void setDataSource(String dataSource) {          contextHolder.set(dataSource);      }        public static String getDataSource() {          return contextHolder.get();      }        public static void clearDataSource() {          contextHolder.remove();      }  }  

自定义@DataSource注解

在需要切换数据的Dao添加此注解

/**   * 备注:自定义数据源选择注解   **/  @Target(ElementType.METHOD)  @Retention(RetentionPolicy.RUNTIME)  @Documented  public @interface DataSource {      String name() default "";  }  

Aop切面类配置

@Aspect  @Component  public class DataSourceAspect {        @Pointcut("@annotation(com.xiaobin.annotation.DataSource)")      public void dataSourcePointCut() {        }        @Around("dataSourcePointCut()")      public Object around(ProceedingJoinPoint point) throws Throwable {          MethodSignature signature = (MethodSignature) point.getSignature();          Method method = signature.getMethod();            DataSource dataSource = method.getAnnotation(DataSource.class);          if(dataSource == null){              DynamicDataSource.setDataSource("xiaobin-master");          }else {              DynamicDataSource.setDataSource(dataSource.name());          }            try {              return point.proceed();          } finally {              DynamicDataSource.clearDataSource();          }      }  }

启动配置注解信息,重要(不然运行会报错)

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})  @MapperScan(basePackages = "com.xiaobin.mapper")  @Import({DynamicDataSourceConfig.class})  public class StartApp {      public static void main(String[] args) {          SpringApplication.run(StartApp.class);      }  }

测试controller

@RestController  @RequestMapping  public class UserController {        @Autowired      private UserMapper userMapper;        @GetMapping("/{name}/list")      public List<TUser> list(@PathVariable("name")String name){          if(name.equals("master")){              return userMapper.queryAllWithMaster();          }else{              return userMapper.queryAllWithSlave();          }      }  }

效果图

更具路径传值,进行主从数据源切换