springBoot学习笔记(2.5)—— 整合mybatis配置多数据源

一、配置步骤

1.引入jar包

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.6.2</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.example</groupId>
  12. <artifactId>springboot-datasource</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>springboot-datasource</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-data-jdbc</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-jdbc</artifactId>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-web</artifactId>
  31. </dependency>
  32. <dependency>
  33. <groupId>mysql</groupId>
  34. <artifactId>mysql-connector-java</artifactId>
  35. <scope>runtime</scope>
  36. </dependency>
  37. <dependency>
  38. <groupId>org.projectlombok</groupId>
  39. <artifactId>lombok</artifactId>
  40. <optional>true</optional>
  41. </dependency>
  42. <dependency>
  43. <groupId>org.springframework.boot</groupId>
  44. <artifactId>spring-boot-starter-test</artifactId>
  45. <scope>test</scope>
  46. </dependency>
  47. <dependency>
  48. <groupId>org.mybatis.spring.boot</groupId>
  49. <artifactId>mybatis-spring-boot-starter</artifactId>
  50. <version>1.3.1</version>
  51. </dependency>
  52. <!--分数据源-->
  53. <!-- 阿里连接池-->
  54. <!--分数据源-->
  55. <dependency>
  56. <groupId>com.alibaba</groupId>
  57. <artifactId>druid-spring-boot-starter</artifactId>
  58. <version>1.1.10 </version>
  59. </dependency>
  60. <dependency>
  61. <groupId>com.alibaba</groupId>
  62. <artifactId>druid</artifactId>
  63. <version>1.1.0</version>
  64. </dependency>
  65. <dependency>
  66. <groupId>org.springframework.boot</groupId>
  67. <artifactId>spring-boot-starter-aop</artifactId>
  68. </dependency>
  69. </dependencies>
  70. <build>
  71. <plugins>
  72. <plugin>
  73. <groupId>org.springframework.boot</groupId>
  74. <artifactId>spring-boot-maven-plugin</artifactId>
  75. <configuration>
  76. <excludes>
  77. <exclude>
  78. <groupId>org.projectlombok</groupId>
  79. <artifactId>lombok</artifactId>
  80. </exclude>
  81. </excludes>
  82. </configuration>
  83. </plugin>
  84. </plugins>
  85. </build>
  86. </project>

2.配置项目文件

  1. spring:
  2. datasource:
  3. driver-class-name: com.mysql.cj.jdbc.Driver
  4. druid:
  5. #数据源1
  6. first:
  7. # 数据源基本配置
  8. url: jdbc:mysql://101.34.49.127:3306/springBootAll?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
  9. username: root
  10. password: 123456
  11. # 数据源2
  12. second:
  13. url: jdbc:mysql://localhost:3306/springBootAll?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
  14. username: root
  15. password: 123456
  16. mybatis:
  17. mapper-locations: classpath:mybatis/mapper/*.xml
  18. server:
  19. port: 8082 # 配置项目启动端口

3.数据源切换配置

3.1 项目文件截图

springBoot学习笔记(2.5)—— 整合mybatis配置多数据源 - 图1

3.2 CurDataSouce类切换数据源的注释

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface CurDataSource {
  5. String name() default "";
  6. }

3.3 DataSourceAspect类多数据源切面处理

  1. @Slf4j
  2. @Aspect
  3. @Component
  4. public class DataSourceAspect implements Ordered {
  5. @Pointcut("@annotation(com.example.springbootdatasource.datasource.CurDataSource)")
  6. public void dataSourcePointCut() {
  7. }
  8. @Around("dataSourcePointCut()")
  9. public Object around(ProceedingJoinPoint point) throws Throwable {
  10. MethodSignature signature = (MethodSignature) point.getSignature();
  11. Method method = signature.getMethod();
  12. CurDataSource ds = method.getAnnotation(CurDataSource.class);
  13. if (ds == null) {
  14. DynamicDataSource.setDataSource(DataSourceNames.FIRST);
  15. log.debug("set datasource is " + DataSourceNames.FIRST);
  16. } else {
  17. DynamicDataSource.setDataSource(ds.name());
  18. log.debug("set datasource is " + ds.name());
  19. }
  20. try {
  21. return point.proceed();
  22. } finally {
  23. DynamicDataSource.clearDataSource();
  24. log.debug("clean datasource");
  25. }
  26. }
  27. @Override
  28. public int getOrder() {
  29. return 1;
  30. }
  31. }

3.4 DataSourceNames类枚举数据源

  1. public interface DataSourceNames {
  2. String FIRST = "first";
  3. String SECOND = "second";
  4. }

3.5 DynamicDataSource类

  1. /**
  2. * 扩展 Spring 的 AbstractRoutingDataSource 抽象类,重写 determineCurrentLookupKey 方法
  3. * 动态数据源
  4. * determineCurrentLookupKey() 方法决定使用哪个数据源
  5. *
  6. * @author xiaohe
  7. * @version V1.0.0
  8. */
  9. public class DynamicDataSource extends AbstractRoutingDataSource {
  10. /**
  11. * ThreadLocal 用于提供线程局部变量,在多线程环境可以保证各个线程里的变量独立于其它线程里的变量。
  12. * 也就是说 ThreadLocal 可以为每个线程创建一个【单独的变量副本】,相当于线程的 private static 类型变量。
  13. */
  14. private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
  15. /**
  16. * 决定使用哪个数据源之前需要把多个数据源的信息以及默认数据源信息配置好
  17. *
  18. * @param defaultTargetDataSource 默认数据源
  19. * @param targetDataSources 目标数据源
  20. */
  21. public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
  22. super.setDefaultTargetDataSource(defaultTargetDataSource);
  23. super.setTargetDataSources(targetDataSources);
  24. super.afterPropertiesSet();
  25. }
  26. @Override
  27. protected Object determineCurrentLookupKey() {
  28. return getDataSource();
  29. }
  30. public static void setDataSource(String dataSource) {
  31. CONTEXT_HOLDER.set(dataSource);
  32. }
  33. public static String getDataSource() {
  34. return CONTEXT_HOLDER.get();
  35. }
  36. public static void clearDataSource() {
  37. CONTEXT_HOLDER.remove();
  38. }
  39. }

3.6 DynamicDataSourceConfig类

  1. /**
  2. * 配置多数据源
  3. * @author xiaohe
  4. * @version V1.0.0
  5. */
  6. @Configuration
  7. public class DynamicDataSourceConfig {
  8. @Bean
  9. @ConfigurationProperties("spring.datasource.druid.first")
  10. public DataSource firstDataSource(){
  11. return DruidDataSourceBuilder.create().build();
  12. }
  13. @Bean
  14. @ConfigurationProperties("spring.datasource.druid.second")
  15. public DataSource secondDataSource(){
  16. return DruidDataSourceBuilder.create().build();
  17. }
  18. @Bean
  19. @Primary
  20. public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource) {
  21. Map<Object, Object> targetDataSources = new HashMap<>(5);
  22. targetDataSources.put(DataSourceNames.FIRST, firstDataSource);
  23. targetDataSources.put(DataSourceNames.SECOND, secondDataSource);
  24. return new DynamicDataSource(firstDataSource, targetDataSources);
  25. }
  26. }

4.springboot主方法

  1. //启动时不引入数据库配置
  2. @SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
  3. @MapperScan(basePackages = "com.example.springbootdatasource")
  4. @EnableScheduling
  5. @EnableAspectJAutoProxy(exposeProxy = true)
  6. @Import({DynamicDataSourceConfig.class})
  7. public class SpringbootDatasourceApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(SpringbootDatasourceApplication.class, args);
  10. }
  11. }

5.controller层接口

  1. @Controller
  2. @RequestMapping("userController")
  3. public class UserController {
  4. @Resource
  5. UserService userService;
  6. /****
  7. * description: findUser
  8. * version: 1.0 ->
  9. * date: 2022/1/28 15:11
  10. * author: xiaYZ
  11. * iteration: 迭代说明
  12. * @param id
  13. * @return java.lang.String
  14. */
  15. @ResponseBody
  16. @GetMapping("findUserFromFirst")
  17. @Description("申明使用数据源一进行操作")
  18. public String findUserFromFirst(Integer id){
  19. User user = new User();
  20. try{
  21. user = userService.selectDataFromFirst(id);
  22. }catch (Exception e){
  23. e.printStackTrace();
  24. }
  25. return user.toString();
  26. }
  27. /***
  28. * description: findUserSecond
  29. * version: 1.0 ->
  30. * date: 2022/2/1 18:14
  31. * author: xiaYZ
  32. * iteration: 迭代说明
  33. * @param id
  34. * @return java.lang.String
  35. */
  36. @ResponseBody
  37. @GetMapping("findUserFromSecond")
  38. @Description("查询用户数据从数据源二")
  39. public String findUserFromSecond(Integer id){
  40. User user = new User();
  41. try{
  42. user = userService.selectDataSecond(id);
  43. }catch (Exception e){
  44. e.printStackTrace();
  45. }
  46. return user.toString();
  47. }
  48. }

6.service层方法

  1. @Service
  2. public class UserService{
  3. @Resource
  4. private UserMapper userMapper;
  5. /**
  6. * description: 申明使用数据源一进行操作
  7. * version: 1.0
  8. * date: 2022/2/1 18:10
  9. * author: xiaYZ
  10. * iteration: 迭代说明
  11. * @param id
  12. * @return
  13. */
  14. @CurDataSource(name = DataSourceNames.FIRST)
  15. public User selectDataFromFirst(Integer id) {
  16. return userMapper.selectByPrimaryKey(id);
  17. }
  18. /**
  19. * description: 申明使用数据源二进行操作
  20. * version: 1.0
  21. * date: 2022/2/1 19:27
  22. * author: xiaYZ
  23. * iteration: 迭代说明
  24. * @param id
  25. * @return
  26. */
  27. @CurDataSource(name = DataSourceNames.SECOND)
  28. public User selectDataSecond(Integer id){
  29. return userMapper.selectByPrimaryKey(id);
  30. }
  31. }

使用@CurDataSource注解声明使用那个数据源

二、项目运行截图

1. 数据库截图

1.1本地数据截图

springBoot学习笔记(2.5)—— 整合mybatis配置多数据源 - 图2

1.2 服务器上数据库截图

springBoot学习笔记(2.5)—— 整合mybatis配置多数据源 - 图3

2.接口调用截图

2.1 服务器数据源接口截图

springBoot学习笔记(2.5)—— 整合mybatis配置多数据源 - 图4

2.2 本地接口数据源截图

springBoot学习笔记(2.5)—— 整合mybatis配置多数据源 - 图5

总结

  1. 引入对应jar包
  2. 构建数据源切换配置
  3. service层使用@CurDataSource注解切换配置,如果没有使用此注解默认使用上一个接口的数据源

项目源码