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

这篇具有很好参考价值的文章主要介绍了Spring Boot + MyBatis-Plus 实现 MySQL 主从复制动态数据源切换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

MySQL 主从复制是一种常见的数据库架构,它可以提高数据库的性能和可用性。动态数据源切换则可以根据业务需求,在不同场景下使用不同的数据源,比如在读多写少的场景下,可以通过切换到从库来分担主库的压力

在本文中,我们将介绍如何在 Spring Boot 中实现 MySQL 动态数据源切换,使用 MyBatis-Plus 进行数据库操作

那么接下来我们开始项目实现,项目结构如下

前备:可以提前导入sql

create table tb_tutorial
(
    id          bigint auto_increment comment '主键ID'
        primary key,
    title       varchar(40) null comment '标题',
    description varchar(30) null comment '描述',
    published   tinyint     null comment '1 表示发布 0 表示未发布'
);

-- 在从库进行数据添加
INSERT INTO user_db.tb_tutorial
(id, title, description, published)
VALUES(1758812356898889, 'savle', 'savle', 1);

1.引入依赖

在项目的的pom.xml文件中引入Spring Boot和MyBatis-Plus的相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.7.15</version>
    </parent>

    <groupId>com.zbbmeta</groupId>
    <artifactId>spring-boot-dynamic-master-slave</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <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>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2. 配置数据源

application.yml文件中配置主从数据源信息。注意这里我们要搭建主从数据库,本文只是在一个mysql实例中创建两个库,里面存在相同表
正确应该是两个不同的mysql实例,作者暂时没有环境Spring Boot + MyBatis-Plus 实现 MySQL 主从复制动态数据源切换

server:
  port: 8082

spring:
  datasource:
    master:
      username: root
      password: root
      url: jdbc:mysql://localhost:3306/webapi?useUnicode=true&characterEncoding=utf8
      driver-class-name: com.mysql.cj.jdbc.Driver
    slave:
      username: root
      password: root
      url: jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=utf8
      driver-class-name: com.mysql.cj.jdbc.Driver


mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml

3. 创建DatabaseType 枚举类型

创建DatabaseType 枚举类型,用于切换数据源时,确定连接的是那个数据源

com.zbbmeta.config包下创建DatabaseType枚举类型

// 定义一个枚举类型 DatabaseType,表示系统中的数据库类型
public enum DatabaseType {
    MASTER,  // 主数据库类型
    SLAVE    // 从数据库类型
}

4. 配置数据源上下文

com.zbbmeta.holder包下创建一个DataSourceContextHolder类用于保存和获取当前线程使用的数据源类型

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. 配置动态数据源

我们创建了一个 DynamicDataSource 类,继承 AbstractRoutingDataSource,用于实现动态数据源的切换。

AbstractRoutingDataSource 是 Spring Framework 提供的一个抽象数据源类,用于实现动态数据源切换它允许应用程序在运行时动态地切换到不同的数据源,从而支持多数据源的场景,比如数据库读写分离、主从复制等

AbstractRoutingDataSource介绍:

  • 动态数据源切换: AbstractRoutingDataSource 的核心思想是根据某个键值(lookup key)来决定使用哪个具体的数据源。这个键值是通过 determineCurrentLookupKey() 方法提供

  • 抽象类: AbstractRoutingDataSource 是一个抽象类,它提供了模板方法 determineCurrentLookupKey(),需要由子类实现

  • 实现 javax.sql.DataSource 接口: AbstractRoutingDataSource 实现了 javax.sql.DataSource 接口,因此可以像常规数据源一样被用于与数据库的交互。

  • 在 Spring 配置中使用: 在 Spring 的配置中,我们可以将 AbstractRoutingDataSource 配置为数据源 bean,并将真实的数据源作为其目标数据源。在需要切换数据源的时候,调用 determineCurrentLookupKey() 方法,它将返回用于切换数据源的键值。

com.zbbmeta.config包下创建DynamicDataSource

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        // 从数据源上下文获取数据源类型
        return DataSourceContextHolder.getDataSourceType();
    }
}

DynamicDataSource类中重写determineCurrentLookupKey()方法: 在这个方法中,我们通过调用 DataSourceContextHolder.getDataSourceType() 来获取当前线程持有的数据源类型。这个方法的返回值将被用作数据源的 lookup key,从而实现动态切换。

6. 添加DataSource注解类

在·com.zbbmeta.annotation包下创建DataSource注解类,这是一个自定义注解,用于标记在类或方法上,以指定数据源的类型。下面是对这段代码的注解说明

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

    // 默认是从数据库
    DatabaseType type() default DatabaseType.SLAVE;

}

注解说明

  • @interface DataSource: 这是一个注解的声明,用于创建名为 DataSource 的自定义注解。

  • @Target({ElementType.METHOD, ElementType.TYPE})@Target 注解表示此注解可以用于类和方法。在这里,DataSource 注解可以标注在类和方法上。

  • @Retention(RetentionPolicy.RUNTIME): @Retention 注解表示这个注解的生命周期,即在运行时仍然可用。这是因为我们希望在运行时通过反射获取注解信息。

  • DatabaseType type() default DatabaseType.SLAVE: 这是 DataSource 注解的一个成员变量。它是一个枚举类型的变量,表示数据库类型,默认值为 SLAVE。通过这个成员变量,我们可以在使用 DataSource 注解时指定使用的数据源类型

7. 配置数据源切换切面

com.zbbmeta.aspect报下创建一个切面类DataSourceAspect,用于在执行数据库操作前动态切换数据源。

@Aspect
@Component
@EnableAspectJAutoProxy
public class DataSourceAspect {
// 定义切点,匹配使用了 @DataSource 注解的方法
    @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 dataSource = method.getAnnotation(DataSource.class);
        if (dataSource != null) {
            // 切换数据源类型
            DatabaseContextHolder.setDatabaseType(dataSource.type());
        }

        try {
            // 执行目标方法
            return point.proceed();
        } finally {
            // 清除数据源类型,确保线程安全
            DatabaseContextHolder.clearDatabaseType();
        }
    }
}

8. 创建DataSourceConfig

com.zbbmeta.config包下创建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();

    }
}

9 创建DataSourceConfig

com.zbbmeta.config包下创建DynamicDataSourceConfig类中配置MyBatis-Plus的相关内容。

@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);
    }
}

10. 测试

使用MybatisX生成代码,并且创建com.zbbmeta.controller包下创建TutorialController类,并且在需要切换数据源的方法上使用 @DataSource 注解,切面将根据该注解的配置在方法执行前后进行数据源切换。

@RestController
public class TutorialController {


    @Autowired
    private TutorialService tutorialService;


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

    }

    /**
     *
     * 功能: 在主库创建数据
     * @return {@link Boolean}
     * @author luoheng
     */
    @DataSource(type = DatabaseType.MASTER)
    @GetMapping("/create")
    public Boolean create(){

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

        return tutorialService.save(tutorial);
    }
}

使用测试工具,或者浏览器发送请求。

这里由于主,从没有数据同步,直接请求会没有数据。我们可以手动新增一下测试数据

Get请求:http://localhost:8082/list
返回结果:[{"id":10,"title":"savle","description":"savle","published":1}]


Get请求:http://localhost:8082/create
返回结果:true

这样就可以实现动态数据切换,实现读写分离。但是这个时候会数据库不一致,这里提供一篇文章,来实现主从数据库同步。

实现两个MySQL数据库之间数据同步的方案_两个mysql数据库实时同步-CSDN博客文章来源地址https://www.toymoban.com/news/detail-825456.html

到了这里,关于Spring Boot + MyBatis-Plus 实现 MySQL 主从复制动态数据源切换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot 整合MyBatis-Plus

    😀前言 本篇博文是关于Spring Boot 整合MyBatis-Plus的,希望你能够喜欢😊 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的满意是我的动力😉😉 💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,感谢大家的观看🥰

    2024年02月11日
    浏览(38)
  • Spring Boot整合MyBatis-Plus

    引言 在现代软件开发中,我们经常需要处理大量的数据。为了有效地管理这些数据,我们需要使用一些强大的框架。其中,Spring Boot和MyBatis-Plus是两个非常流行的框架。Spring Boot是一个基于Spring的开源Java框架,可以用于创建独立的、生产级别的Spring应用。MyBatis-Plus是一个MyB

    2024年01月19日
    浏览(48)
  • spring boot mybatis-plus操作实践

    1、先建一个数据表实体类 2、service目录下新建接口IDeptService,然后扩展mp的IService 3、service目录的impl目录下新建类 DeptServiceImpl,扩展mp的ServiceImpl,实现接口IDeptService,然后注册@Service 注解 4、DeptMapper 接口需要扩展mp的BaseMapper接口 5、调试一下看看是否可以使用

    2024年02月01日
    浏览(39)
  • spring boot集成mybatis-plus——Mybatis Plus 查询数据(图文讲解)

     更新时间 2023-01-03 16:07:12 大家好,我是小哈。 本小节中,我们将学习如何通过 Mybatis Plus 查询数据库表中的数据。 在前面小节中,我们已经定义好了一个用于测试的用户表, 执行脚本如下: 定义一个名为  User  实体类: 不明白 Mybatis Plus 实体类注解的小伙伴,可参考前面

    2024年02月02日
    浏览(47)
  • spring boot3整合mybatis-plus

    添加依赖 配置属性信息 编写业务逻辑测试代码 配置mybatis-plus分页插件 配置mybatis-plus之属性自动填充 如图所示 1、添加依赖 2、配置属性 3、编写测试代码 4、XML文件 5、测试数据是否能走通

    2024年03月12日
    浏览(46)
  • spring boot+mybatis-plus配置读写分离

    对于mysql主从机制的读写分离,对于写操作写入主库,读取操作读取从库 一、安装依赖 二、配置文件配置数据源 三、在service,如果是读取操作的话,则需要加上注解@DS(“slave”)即可,可看如下示例

    2024年01月25日
    浏览(39)
  • Spring Boot学习随笔- 集成MyBatis-Plus(三)自定义SQL、分页实现(PaginationInterceptor )、更新和删除详细方法

    学习视频:【编程不良人】Mybatis-Plus整合SpringBoot实战教程,提高的你开发效率,后端人员必备! 自定义mapper文件是为了应对一些更复杂的查询场景,首先先配置映射路径 由于这里的mapper文件放在java文件夹中,所以要在pom.xml里进行配置 mapper 测试 在MyBatis Plus中, 物理分页 和 内

    2024年02月03日
    浏览(43)
  • spring boot集成mybatis-plus——Mybatis Plus 批量 Insert_新增数据(图文讲解)

     更新时间 2023-01-10 16:02:58 大家好,我是小哈。 本小节中,我们将学习如何通过 Mybatis Plus 实现 MySQL 批量插入数据。 先抛出一个问题:假设老板给你下了个任务,向数据库中添加 100 万条数据,并且不能耗时太久! 通常来说,我们向 MySQL 中新增一条记录,SQL 语句类似如下:

    2024年02月04日
    浏览(35)
  • 从零开始学Spring Boot系列-集成MyBatis-Plus

    在Spring Boot应用开发中,MyBatis-Plus是一个强大且易于使用的MyBatis增强工具,它提供了很多实用的功能,如代码生成器、条件构造器、分页插件等,极大地简化了MyBatis的使用和配置。本篇文章将指导大家如何在Spring Boot项目中集成MyBatis-Plus。 首先,确保你已经安装了Java开发环

    2024年04月08日
    浏览(66)
  • spring boot集成mybatis-plus——Mybatis Plus 新增数据并返回主键 ID(图文讲解)

     更新时间 2023-01-10 15:37:37 大家好,我是小哈。 本小节中,我们将学习如何通过 Mybatis Plus 框架给数据库表新增数据,主要内容思维导图如下: Mybatis Plus 新增数据思维导图 为了演示新增数据,在前面小节中,我们已经定义好了一个用于测试的用户表, 执行脚本如下: 定义一

    2024年02月02日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包