Spring Boot项目MySQL数据源切换

由于在主库发现的我的一条SQL的慢查询、之前都是直接连一个数据库、后面让他改成查询的SQL连另一台从库。

于是我第一时间打开了大家的百度、后续总结复制粘贴了一个完整的案例并线上使用了、环境版本不一样可能使用的配置不一样、所以仅供参考。

Spring Boot、Druid、Mybatis、MySQL

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.3.RELEASE</version>
</parent>
<!-- Mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.2</version>
</dependency>
<!-- mysql 数据库驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.25</version>
</dependency>
<!-- druid 数据库连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.17</version>
</dependency>
yaml 复制代码
spring:
  datasource:
    master:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: root
      password: 123456
    slave:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: root
      password: 123456
      # druid 连接池配置接着往下配置就OK
      max-active: 12
java 复制代码
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {
    public static final String MASTER = "MASTER"; // 写
    public static final String SLAVE = "SLAVE"; // 读
    private static final ThreadLocal<String> DYNAMIC_DATASOURCE_KEY = new ThreadLocal<>();
    public static String getDynamicDataSourceKey() {
        String val = DYNAMIC_DATASOURCE_KEY.get();
        return val == null ? DynamicDataSource.MASTER : val;
    }
    public static void setDynamicDataSourceKey(String key) {
        DYNAMIC_DATASOURCE_KEY.set(key);
    }
    public static void removeDynamicDataSourceKey() {
        DYNAMIC_DATASOURCE_KEY.remove();
    }
    @Override
    protected Object determineCurrentLookupKey() {
        String dynamicDataSourceKey = getDynamicDataSourceKey();
        log.info("当前数据源:[{}]", dynamicDataSourceKey);
        return dynamicDataSourceKey;
    }
}
java 复制代码
@Configuration
public class DataSourceConfiguration {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDataSource() {
        return DruidDataSourceBuilder.create().build();
    }
    @Bean("dynamicDataSource")
    public DynamicDataSource dynamicDataSource() {
        DynamicDataSource dynamicRoutingDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>(2);
        targetDataSources.put(DynamicDataSource.MASTER, masterDataSource());
        targetDataSources.put(DynamicDataSource.SLAVE, slaveDataSource());

        dynamicRoutingDataSource.setDefaultTargetDataSource(slaveDataSource());
        dynamicRoutingDataSource.setTargetDataSources(targetDataSources);
        dynamicRoutingDataSource.afterPropertiesSet();
        return dynamicRoutingDataSource;
    }
    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource datasource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        // 映射文件地址
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        // 所有Entity别名类所在包
        bean.setTypeAliasesPackage("com.suka.entity");
        return bean.getObject();
    }
}
java 复制代码
@Slf4j
@Aspect
@Order(1)
@Component
public class DataSourceAspect {
    @Pointcut("execution(* com.suka.mapper.*.*(..))")
    public void dsPointCut() {
    }
    @Around("dsPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        String methodName = signature.getMethod().getName();
        // get/sel/select/find 开的头的Mapper类中的方法就切换。
        if (methodName.startsWith("get") || methodName.startsWith("sel")
                || methodName.startsWith("select") || methodName.startsWith("find")) {
            DynamicDataSource.setDynamicDataSourceKey(DynamicDataSource.SLAVE);
        }
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.removeDynamicDataSourceKey();
        }
    }
}

两个注意点:DataSourceAspect类是需要引入AOP依赖、sqlSessionFactory是Mybatis需要的、里面可以配置一些扫描包的配置以及类别名之类相关Mybatis的配置信息。

问题来了、如何校验我这个查询方法或者插入方法是走的那个配置的数据源呢、你去把配置文件中的数据库写一个错的不就可以校验了、如果报错了就证明是用的这个配置的数据源!!!

相关推荐
可观测性用观测云3 小时前
Pyroscope Java 接入最佳实践
java
气π4 小时前
【JavaWeb】——(若依 + AI)-基础学习笔记
java·spring boot·笔记·学习·java-ee·mybatis·ruoyi
阿里云云原生4 小时前
AgentScope Java 1.0:从模型到应用,AI Agent 全生命周期管理利器!
java·云原生
Cat God 0074 小时前
SQL使用及注意事项
数据库·sql·mysql
running up4 小时前
Maven依赖管理和项目构建工具
java·maven
华仔啊4 小时前
如何避免MySQL死锁?资深DBA的9条黄金法则
后端·mysql
@老蝴4 小时前
MySQL数据库 - 约束和联合查询
android·数据库·mysql
程序猿20234 小时前
MySQL索引使用--最左前缀法则
数据库·mysql
老华带你飞5 小时前
列车售票|基于springboot 列车售票系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习·spring
java_logo5 小时前
LinuxServer.io LibreOffice 容器化部署指南
java·开发语言·docker·dubbo·openoffice·libreoffice·opensource