Spring Boot + MyBatis-Plus 实现 MySQL 主从复制动态数据源切换

Spring Boot + MyBatis-Plus 实现 MySQL 主从复制动态数据源切换

  • 一、前言
    • [1. 添加依赖](#1. 添加依赖)
    • [2. 配置主从数据源](#2. 配置主从数据源)
    • [3. 创建数据源配置类](#3. 创建数据源配置类)
    • [4. 创建数据源上下文](#4. 创建数据源上下文)
    • [5. 定义数据源类型](#5. 定义数据源类型)
    • [6. 配置数据源切换](#6. 配置数据源切换)
    • [7. 创建DynamicDataSourceConfig](#7. 创建DynamicDataSourceConfig)
    • [8. 创建DynamicRoutingDataSource](#8. 创建DynamicRoutingDataSource)
    • [9. 创建注解](#9. 创建注解)
    • [10. 使用注解](#10. 使用注解)

一、前言

下面是一个示例代码,展示如何在 Spring Boot 应用中实现 MySQL 主从复制的数据源动态切换。我们将使用 Spring Boot 和 MyBatis-Plus,并且结合 Spring 的动态数据源切换功能。

1. 添加依赖

首先,确保在 pom.xml 文件中添加了必要的依赖:

xml 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.20</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

    </dependencies>

2. 配置主从数据源

application.ymlapplication.properties 中配置主从数据源:

yaml 复制代码
server:
  port: 8082

spring:
  datasource:
    master:
      url: jdbc:mysql://master-db-host:3306/your_database?useSSL=false
      username: your_username
      password: your_password
      driver-class-name: com.mysql.cj.jdbc.Driver
    slave:
      url: jdbc:mysql://slave-db-host:3306/your_database?useSSL=false
      username: your_username
      password: your_password
      driver-class-name: com.mysql.cj.jdbc.Driver
      
mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml

3. 创建数据源配置类

DataSourceConfig 中配置数据源和动态路由:

java 复制代码
@Configuration
@Data
public class DataSourceConfig {
    @Value("${spring.datasource.master.url}")
    private String dbUrl;
    @Value("${spring.datasource.master.username}")
    private String username;
    @Value("${spring.datasource.master.password}")
    private String password;
    @Value("${spring.datasource.master.driver-class-name}")
    private String driverClassName;


    @Value("${spring.datasource.slave.url}")
    private String slaveDbUrl;
    @Value("${spring.datasource.slave.username}")
    private String slaveUsername;
    @Value("${spring.datasource.slave.password}")
    private String slavePassword;
    @Value("${spring.datasource.slave.driver-class-name}")
    private String slaveDriverClassName;


    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create()
                .driverClassName(driverClassName)
                .url(dbUrl)
                .username(username)
                .password(password)
                .build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDataSource() {

        return DataSourceBuilder.create()
                .driverClassName(slaveDriverClassName)
                .url(slaveDbUrl)
                .username(slaveUsername)
                .password(slavePassword)
                .build();

    }
}

4. 创建数据源上下文

DatabaseContextHolder 用于管理当前线程的数据源类型:

java 复制代码
public class DatabaseContextHolder {

    private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();

    public static void setDatabaseType(DatabaseType databaseType) {
        contextHolder.set(databaseType);
    }

    public static DatabaseType getDatabaseType() {
        return contextHolder.get();
    }

    public static void clearDatabaseType() {
        contextHolder.remove();
    }
}

5. 定义数据源类型

DatabaseType 枚举定义了数据源类型:

java 复制代码
public enum DatabaseType {
    MASTER,
    SLAVE
}

6. 配置数据源切换

使用 AOP 来控制数据源切换,可以定义一个切面来切换数据源:

java 复制代码
@Aspect
@Component
@EnableAspectJAutoProxy
public class DataSourceAspect {



    @Pointcut("@annotation(com.zbbmeta.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) {
            DatabaseContextHolder.setDatabaseType(dataSource.type());
        }

        try {
            return point.proceed();
        } finally {
            DatabaseContextHolder.clearDatabaseType();
        }
    }

}

7. 创建DynamicDataSourceConfig

java 复制代码
@Configuration
@MapperScan("com.zbbmeta.mapper")
public class DynamicDataSourceConfig {
    @Autowired
    private DataSource masterDataSource;

    @Autowired
    private DataSource slaveDataSource;

    // 配置动态数据源
    @Bean
    @Primary
    public DataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DatabaseType.MASTER, masterDataSource);
        targetDataSources.put(DatabaseType.SLAVE, slaveDataSource);

        DynamicRoutingDataSource dynamicDataSource = new DynamicRoutingDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource); // 设置默认数据源
        return dynamicDataSource;
    }

    // 配置 MyBatis 的 SqlSessionFactory
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dynamicDataSource) throws Exception {
        MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dynamicDataSource);

        // 设置要扫描的 mapper 接口和 XML 文件路径
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        sessionFactoryBean.setTypeAliasesPackage("com.zbbmeta.entity");  // 设置实体类包路径

        return sessionFactoryBean.getObject();
    }

    // 配置 MyBatis 的 SqlSessionTemplate
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

8. 创建DynamicRoutingDataSource

复制代码
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DatabaseContextHolder.getDatabaseType();
    }
}

9. 创建注解

注解用于标记需要读操作的方法:

java 复制代码
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {

    DatabaseType type() default DatabaseType.SLAVE;

}

10. 使用注解

java 复制代码
@RestController
public class TutorialController {


    @Autowired
    private TutorialService tutorialService;


    @DataSource
    @GetMapping("/list")
    public List<Tutorial> list(){
        return tutorialService.list();

    }

    @DataSource(type = DatabaseType.MASTER)
    @GetMapping("/create")
    public Boolean create(){

        Tutorial tutorial = new Tutorial();
        tutorial.setTitle("master");
        tutorial.setDescription("master");

        return tutorialService.save(tutorial);
    }
}

这个示例展示了如何使用 Spring Boot 和 MyBatis-Plus 实现 MySQL 主从复制的数据源切换。你可以根据实际情况调整配置和代码。

相关推荐
星马梦缘4 小时前
数据库作战记录1
数据库·sql·mysql
鸡蛋灌Bean7 小时前
MySQL优化系列
数据库·mysql
敲代码的嘎仔9 小时前
Java后端面试——SSM框架面试题
java·面试·职场和发展·mybatis·ssm·springboot·八股
ruanyongjing9 小时前
SpringBoot3 整合 Mybatis 完整版
mybatis
彭于晏Yan10 小时前
MQTT消息服务
spring boot·后端·中间件
indexsunny11 小时前
互联网大厂Java面试实战:从Spring Boot到微服务架构的深度解析
java·spring boot·spring cloud·kafka·prometheus·security·microservices
java1234_小锋11 小时前
分享一套优质的SpringBoot+Vue咖啡商城系统
vue.js·spring boot·咖啡商城
FirstFrost --sy12 小时前
MySQL复合查询
数据库·mysql
imuliuliang12 小时前
MySQL的底层原理与架构
数据库·mysql·架构
悟空码字12 小时前
滑块拼图验证:SpringBoot完整实现+轨迹验证+Redis分布式方案
java·spring boot·后端