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();          }      }  }

效果圖

更具路徑傳值,進行主從數據源切換