当前位置: 首页 > news >正文

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

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

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


一、前言

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

1. 添加依赖

首先,确保在 pom.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 中配置主从数据源:

server:port: 8082spring:datasource:master:url: jdbc:mysql://master-db-host:3306/your_database?useSSL=falseusername: your_usernamepassword: your_passworddriver-class-name: com.mysql.cj.jdbc.Driverslave:url: jdbc:mysql://slave-db-host:3306/your_database?useSSL=falseusername: your_usernamepassword: your_passworddriver-class-name: com.mysql.cj.jdbc.Drivermybatis-plus:mapper-locations: classpath*:/mapper/**/*.xml

3. 创建数据源配置类

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

@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 用于管理当前线程的数据源类型:

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 枚举定义了数据源类型:

public enum DatabaseType {MASTER,SLAVE
}

6. 配置数据源切换

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

@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

@Configuration
@MapperScan("com.zbbmeta.mapper")
public class DynamicDataSourceConfig {@Autowiredprivate DataSource masterDataSource;@Autowiredprivate DataSource slaveDataSource;// 配置动态数据源@Bean@Primarypublic 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@Beanpublic 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@Beanpublic SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}
}

8. 创建DynamicRoutingDataSource

public class DynamicRoutingDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DatabaseContextHolder.getDatabaseType();}
}

9. 创建注解

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

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {DatabaseType type() default DatabaseType.SLAVE;}

10. 使用注解

@RestController
public class TutorialController {@Autowiredprivate 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 主从复制的数据源切换。你可以根据实际情况调整配置和代码。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 鸿蒙HarmonyOS开发:如何使用第三方库,加速应用开发
  • MAML算法详解
  • Oracle RAC 集群启动顺序
  • C语言——位运算
  • linux系统使用 docker 来部署web环境 nginx+php7.4 并配置称 docker-compose-mysql.yml 文件
  • 【第一章概述—计算机中的数制】非十进制数到十进制数的转换,八进制转十进制,16进制转十进制。十进制转8进制,十进制转16进制
  • SSRF漏洞实现
  • Flask返回Json格式字符,中文导致unicode乱码问题
  • Unity URP Shader 修改深度让人物不再被地面遮挡
  • 数论之组合数
  • git cherry-pick 合并多个提交
  • Go 调用Rust函数
  • 浅谈线性表——链表
  • AI编程简介
  • 【第69课】Java安全JWT攻防Swagger自动化算法签名密匙Druid未授权
  • Babel配置的不完全指南
  • Java新版本的开发已正式进入轨道,版本号18.3
  • Nodejs和JavaWeb协助开发
  • NSTimer学习笔记
  • ReactNative开发常用的三方模块
  • redis学习笔记(三):列表、集合、有序集合
  • Redux系列x:源码分析
  • Windows Containers 大冒险: 容器网络
  • Yii源码解读-服务定位器(Service Locator)
  • 阿里云购买磁盘后挂载
  • 基于Vue2全家桶的移动端AppDEMO实现
  • 前言-如何学习区块链
  • 深度解析利用ES6进行Promise封装总结
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • raise 与 raise ... from 的区别
  • ​ssh免密码登录设置及问题总结
  • ‌移动管家手机智能控制汽车系统
  • ![CDATA[ ]] 是什么东东
  • (06)金属布线——为半导体注入生命的连接
  • (2.2w字)前端单元测试之Jest详解篇
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (33)STM32——485实验笔记
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (原創) 物件導向與老子思想 (OO)
  • ***监测系统的构建(chkrootkit )
  • .NET 8.0 发布到 IIS
  • .NET CORE 第一节 创建基本的 asp.net core
  • .net core Swagger 过滤部分Api
  • .Net Core 笔试1
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .Net OpenCVSharp生成灰度图和二值图
  • .Net 垃圾回收机制原理(二)
  • .NET 项目中发送电子邮件异步处理和错误机制的解决方案
  • .net8.0与halcon编程环境构建
  • @SuppressWarnings注解
  • [AIGC] Nacos:一个简单 yet powerful 的配置中心和服务注册中心
  • [Android] Upload package to device fails #2720
  • [Angular] 笔记 18:Angular Router