Spring+MyBatis实现数据库读写分离方案

Spring+MyBatis实现数据库读写分离方案

一、方案背景与目标

在高并发业务场景中,数据库往往是系统性能的瓶颈,尤其是读操作频繁的业务(如电商商品查询、新闻资讯浏览等)。单一数据库节点无法承载大量的并发读写请求,容易出现响应延迟、连接溢出等问题。

数据库读写分离方案通过将写操作(INSERT、UPDATE、DELETE)路由至主数据库,读操作(SELECT)分发至多个从数据库,结合数据库主从复制机制保证数据一致性,从而实现以下目标:

  • 提升并发处理能力:分散读请求到多个从库,降低主库压力,提高整体吞吐量

  • 提高数据可用性:主库故障时可快速切换,从库可继续提供读服务

  • 优化性能体验:可根据业务需求部署从库至不同地域,降低读请求延迟

  • 简化扩展成本:新增读节点无需修改核心业务逻辑,支持水平扩展

二、核心原理

2.1 主从复制机制

基于MySQL等数据库的主从复制功能,实现主库数据向从库的异步同步,是读写分离的基础。其核心流程如下:

  1. 主库执行写操作后,将操作记录写入二进制日志(binlog)

  2. 从库启动IO线程,连接主库并读取binlog内容,保存至本地中继日志(relaylog)

  3. 从库启动SQL线程,解析中继日志并执行相同操作,实现与主库数据同步

注意:主从复制存在微小延迟(通常毫秒级),需结合业务场景设计延迟容忍策略

2.2 读写路由机制

通过Spring提供的数据源扩展能力,自定义动态数据源路由策略,根据SQL操作类型(读/写)自动切换至对应数据库节点。核心组件包括:

  • 动态数据源:继承Spring的AbstractRoutingDataSource,实现数据源路由逻辑

  • 数据源上下文:通过ThreadLocal存储当前线程的数据源标识(主库/从库)

  • 路由触发:通过注解或AOP切面,在执行SQL前设置数据源标识

三、环境准备

3.1 硬件与软件环境

组件 版本要求 说明
JDK 1.8及以上 支持Spring Boot最新稳定版
Spring Boot 2.x及以上 提供自动配置简化开发
MyBatis 3.5.x及以上 配合MyBatis-Spring-Boot-Starter整合
MySQL 5.7及以上 支持主从复制功能
数据库连接池 HikariCP Spring Boot默认连接池,性能优异

3.2 数据库主从配置(以MySQL为例)

3.2.1 主库配置(master)

修改MySQL配置文件my.cnf:

ini 复制代码
# 主库唯一标识
server-id=1
# 开启二进制日志
log-bin=mysql-bin
# 同步的数据库(可指定多个)
binlog-do-db=test_db
# 忽略同步的数据库
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
# 二进制日志格式(row格式支持全量数据同步)
binlog_format=ROW
# 防止主从同步延迟导致的主键冲突
auto-increment-offset=1
auto-increment-increment=2

3.2.2 从库配置(slave)

修改从库MySQL配置文件my.cnf:

ini 复制代码
# 从库唯一标识(与主库不同)
server-id=2
# 开启中继日志
relay-log=mysql-relay-bin
# 只读模式(仅对非超级用户生效)
read-only=1
# 忽略同步的数据库
replicate-ignore-db=mysql
replicate-ignore-db=information_schema

3.2.3 主从连接配置

  1. 主库创建同步账号并授权:
    CREATE USER 'repl'@'%' IDENTIFIED BY 'Repl@123456'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES;

  2. 查看主库binlog状态:
    SHOW MASTER STATUS; -- 记录File(如mysql-bin.000001)和Position(如154)值

  3. 从库配置主库信息并启动同步:

    `CHANGE MASTER TO

    MASTER_HOST='主库IP',

    MASTER_USER='repl',

    MASTER_PASSWORD='Repl@123456',

    MASTER_LOG_FILE='主库File值',

    MASTER_LOG_POS=主库Position值;

-- 启动从库同步

START SLAVE;

-- 查看同步状态(确保Slave_IO_Running和Slave_SQL_Running均为Yes)

SHOW SLAVE STATUS\G;`

四、核心实现步骤

4.1 项目依赖配置(Maven)

在pom.xml中引入核心依赖:

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.10</version>
    <relativePath/>
</parent>

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

    
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.3.1</version>
    </dependency>

    
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>

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

    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

4.2 配置文件编写(application.yml)

配置主从库数据源信息及MyBatis参数:

yaml 复制代码
spring:
  datasource:
    # 主库数据源
    master:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://主库IP:3306/test_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
      username: root
      password: Master@123456
    # 从库数据源(可配置多个)
    slave:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://从库IP:3306/test_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
      username: root
      password: Slave@123456
    # 连接池配置
    hikari:
      maximum-pool-size: 10
      minimum-idle: 5
      idle-timeout: 300000
      connection-timeout: 20000

# MyBatis配置
mybatis:
  mapper-locations: classpath:mapper/**/*.xml
  type-aliases-package: com.example.demo.entity
  configuration:
    map-underscore-to-camel-case: true # 下划线转驼峰
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志

4.3 动态数据源核心实现

4.3.1 数据源类型枚举

定义数据源标识,区分主库和从库:

java 复制代码
package com.example.demo.datasource;

public enum DataSourceType {
    /**
     * 主库
     */
    MASTER,
    /**
     * 从库
     */
    SLAVE
}

4.3.2 数据源上下文管理

通过ThreadLocal维护当前线程的数据源类型,保证线程安全:

(注:文档部分内容可能由 AI 生成)

相关推荐
Shingmc32 小时前
MySQL表的操作
数据库·mysql
Ada大侦探2 小时前
新手小白学习Power BI第二弹--------《电商销售数据分析与可视化项目》需求展示
数据库·学习·数据分析
忍冬行者2 小时前
kubeadm安装的三个masterd的k8s的etcd数据库故障,如何通过备份数据进行恢复
数据库·kubernetes·etcd
码农阿豪2 小时前
从 Oracle 到金仓:一次真实数据库迁移的避坑实录
数据库·oracle
金海境科技2 小时前
亲测正规数据库修复恢复数据标准
数据库
Hello.Reader2 小时前
Flink SQL 中的 OVER 聚合——为每一行算“窗口统计
数据库·sql·flink
JIngJaneIL2 小时前
基于Java旅游信息推荐系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot·旅游
LSL666_2 小时前
mybatisplus入门案例
数据库·mysql·mybatisplus
ZePingPingZe3 小时前
DriverManager、DataSource、数据库驱动以及数据库连接池的关系
android·数据库·adb