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

news2024/9/22 11:38:09

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: 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 中配置数据源和动态路由:

@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 {
    @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. 创建注解

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

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {

    DatabaseType type() default DatabaseType.SLAVE;

}

10. 使用注解

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2057672.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1.Java:集合

集合作用&#xff1a; 1.动态保存任意多个对象。 2.提供操作对象方法比如add,remove,set,get等方法。 3.使用集合添加&#xff0c;删除代码简洁。 集合分类 集合分为单列集合以及双列集合。 单列集合&#xff1a; 双列集合&#xff1a; Collection接口特点 1.Collection…

【Nginx】 Nginx Rewrite 相关功能

Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求 此功能依靠 PCRE(perl compatible regular expression)&#xff0c;因此编译之前要安装PCRE库 rewrite是nginx服务器的重要功能之一&#xff0c;用于实现URL的重写&#xff0c;URL的重写是非常有用的功能 比…

智慧环卫与智慧城市:以人文本的创新发展之路

智慧环卫与智慧城市&#xff1a;以人文本的创新发展之路 前言智慧环卫与智慧城市 前言 智慧环卫和智慧城市的建设是当今社会发展的重要趋势&#xff0c;它们对于提升城市管理水平、改善居民生活质量具有至关重要的意义。随着国家政策对新型城市建设的大力推动&#xff0c;智慧…

学习 node.js 六 Markdown 转为 html,zlib

目录 Markdown 转为 html 安装 ejs语法 标签含义 1. 纯文本标签 2. 输出经过 HTML 转义的内容 3. 输出非转义的内容(原始内容) marked browserSync zlib gzip deflate gzip 和 deflate 区别 http请求压缩 Markdown 转为 html 什么是markdown&#xff1f; Markdo…

数据库系列之GaussDB数据库高可用部署方案

GaussDB数据库主备架构的基本组件,以及基于华为云底座和轻量化部署TPOPS两种方式的典型高可用部署场景介绍。 1、GaussDB数据库组件 1.1 GaussDB数据库集中式主备集群基本组件 CM由CM Agent、CM Server和OM monitor构成: CM Agent:管理服务组件,由OMM拉起(周期1秒),主要…

ARM32开发——PWM高级定时器

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 需求高级定时器通道互补输出开发流程通道配置 打开互补保护电路完整代码 需求 点亮2个灯&#xff0c;采用互补pwm的方式 高级定时…

【Unity脚本】使用脚本修改游戏对象静态属性

【知识链】Unity -> -> 脚本系统 -> 访问游戏对象 -> 静态属性【摘要】本文介绍了Unity中游戏对象的静态和动态类型&#xff0c;并说明了如何修改静态属性。 文章目录 第一章 Unity中的静与动第二章 静态和动态对象1. 静态对象&#xff08;Static Objects&#xf…

Web服务器——————nginx篇

一.What is Web服务器 Web服务器介绍 Web服务器&#xff08;Web Server&#xff09;是指驻留于因特网上某种类型计算机的程序&#xff0c;该程序可以向Web浏览器&#xff08;如Chrome、Firefox、Safari等&#xff09;等客户端提供文档&#xff0c;也可以放置网站文件&#…

4-1-3 arduino驱动直流电机(电机专项教程)

4-1-3 arduino驱动直流电机&#xff08;电机专项教程&#xff09; 4-1-3 arduino驱动直流电机XY-2.5AD电机控制模块家用直流电源改装成项目制作电源示例程序效果演示 4-1-3 arduino驱动直流电机 Arduino控制直流有刷电机的话&#xff0c;通过H桥电路实现转向控制&#xff0c;以…

C语言——预处理

C语言编译步骤 预处理 编译 汇编 链接 预处理 概念&#xff1a; 预处理就是在源文件&#xff08;如.c文件&#xff09;编译之前&#xff0c;所进行的一部分预备操作&#xff0c;这部分操作是由预处理程序自动来完成;当源文件在编译时&#xff0c;编译器会自动调用预处理程序来…

ESP32神经网络初步使用

摘要 本文档描述了如何使用Python和TensorFlow训练一个简单的神经网络模型来预测正弦函数&#xff0c;并将其部署到ESP32微控制器上。 参考文章 使用Python和Arduino在ESP32上预测正弦函数 - Dapenson - 博客园 (cnblogs.com) 最简单体验TinyML、TensorFlow Lite——ESP32跑…

Android Studio修改默认.m2与Gradle user home缓存位置

Android Studio修改默认.m2与Gradle user home缓存位置 1、修改Gradle user home的方法&#xff1a; android studio配置默认.gradle路径_android studio gradle在哪-CSDN博客文章浏览阅读2k次。当android studio新建一个项目时候&#xff0c;默认的.gradle路径均认为是在c盘的…

若依搭建实践

若依要求版本 JDK>1.8 MySQL>5.7 Maven>3.0 Node >12 Redis >3 一、环境下载及安装 我本地JDK1.8 MySQL9.0.1 Maven3.5.4 Node 20.12.2 Redis 5.0.14.1 在若依官网下载需要的版本&#xff0c;目前若依支持版本有四个&#xff0c;我们根据需要选择对应的版本…

集合及数据结构第五节————ArrayList的介绍和应用

系列文章目录 集合及数据结构第五节————ArrayList的介绍和应用 ArrayList的介绍和应用 什么是ArrayLisArrayList使用简单的洗牌算法杨辉三角 文章目录 系列文章目录集合及数据结构第五节————ArrayList的介绍和应用 ArrayList的介绍和应用 一、ArrayList1.什么是Arra…

鸿蒙 使用 expandSafeArea 实现顶部沉浸式导航

1&#xff0c; 先看效果&#xff1b; // 设置顶部绘制延伸到状态栏.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP]) 2&#xff0c; 直接cv 粘贴代码 // xxx.ets Entry Component struct Example {build() {Column() {Row() {Text().fontSize(40).textAlign(Text…

2_foc转速环_电磁转矩方程与运动方程的传递函数

转速环里面包含有电流环在内&#xff0c;当外面给定转速时&#xff0c;系统通过控制iq来控制电磁转矩&#xff0c;从而电机开始转动。电机在转动的过程&#xff0c;传感器检测到机械角度会改变&#xff0c;也就是说电角度也会改变&#xff0c;由电角度在单位时间的变化&#xf…

【C++ 第十五章】map 和 set 的封装(封装红黑树)

1. map 和 set 的介绍 ⭐map 与 set 分别是STL中的两种序列式容器; 它们是一种树形数据结构的容器&#xff0c;且其的底层构造为一棵红黑树; 而在上一篇文章中提到,其实红黑树本身就是一棵二叉搜索树,是基于二叉搜索树的性质对其增加了平衡的属性来提高其综合性能 ⭐当然也…

ip地址冲突的原因及其解决方法是什么

在当今的信息化时代&#xff0c;网络已成为我们生活和工作中不可或缺的一部分。然而&#xff0c;随着网络设备数量的不断增加&#xff0c;网络管理中的问题也日益凸显&#xff0c;其中IP地址冲突便是常见问题之一。IP地址冲突不仅会导致网络通信不稳定&#xff0c;甚至可能使设…

详解栈和队列

目录&#xff1a; 1.栈 2.队列 一、 栈&#xff08;Stack&#xff09; 1.1 概念&#xff1a; 栈是一种特殊的线性表&#xff0c;只允许在固定的一端进行插入和删除元素的操作。进行插入元素的一端叫做栈顶&#xff0c;另一端叫做栈底。从数据结构的角度出发&#xff0c;栈中…

k8s-deployment控制器

k8s-deployment控制器 1、yaml文件标签学习-指定pod在哪台节点上创建 强制指定pod在指定节点上创建&#xff1a; --- apiVersion: apps/v1 kind: Deployment metadata:name: my-deployment spec:replicas: 3selector:matchLabels:app: web1template:metadata:labels:app: web1…