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 生成)

相关推荐
陌上丨6 小时前
Redis的Key和Value的设计原则有哪些?
数据库·redis·缓存
AI_56787 小时前
AWS EC2新手入门:6步带你从零启动实例
大数据·数据库·人工智能·机器学习·aws
ccecw7 小时前
Mysql ONLY_FULL_GROUP_BY模式详解、group by非查询字段报错
数据库·mysql
JH30737 小时前
达梦数据库与MySQL的核心差异解析:从特性到实践
数据库·mysql
数据知道7 小时前
PostgreSQL 核心原理:如何利用多核 CPU 加速大数据量扫描(并行查询)
数据库·postgresql
麦聪聊数据9 小时前
Web 原生架构如何重塑企业级数据库协作流?
数据库·sql·低代码·架构
未来之窗软件服务9 小时前
数据库优化提速(四)新加坡房产系统开发数据库表结构—仙盟创梦IDE
数据库·数据库优化·计算机软考
程序员侠客行9 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
Goat恶霸詹姆斯10 小时前
mysql常用语句
数据库·mysql·oracle
大模型玩家七七10 小时前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习