news 2026/7/2 5:37:24

SpringCloud进阶--MySQL主从复制、分库分表、读写分离的实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringCloud进阶--MySQL主从复制、分库分表、读写分离的实现

注释掉 mysqlx-bind-address = 127.0.0.1

然后重启MySQL服务。

  1. 配置主库,给刚才创建的用户分配一个主从复制的权限即可:
grant replication slave on *.* to test; flush privileges;

这时主库就搭建完成了,然后开始进行从库配置

  1. 配置从库配置文件:
# 这里需要将server-id配置为其他的值(默认1),所有MySQL主从实例的id必须唯一!,不然会开启失败 server-id = 2
  1. 进入数据库,输入:
change replication source to SOURCE_HOST='192.168.0.8',SOURCE_USER='test',SOURCE_PASSWORD='123456',SOURCE_LOG_FILE='BINLOG.000004',SOURCE_LOG_POS=591;

SOURCE_HOST -- 主库地址

SOURCE_LOG_FILE-- 二进制日志,就是主库的日志文件(在主库输入 show master status 可以查到)

SOURCE_LOG_POS -- 日志的偏移地址(在主库输入 show master status 可以查到)

  1. 执行完后输入start replica;

这时从库就启动了!

输入show replica status\G;

最关键的就是Replica_IO_Running和Replica_SQL_Running必须同时为yes才可以!

实际上从库会创建2个线程,一个线程复制与主库进行通信,获取二进制日志,暂时存放到一个中间表(Relay_Log)中,另一个线程将中间表保存的二进制日志信息进程执行,然后插入到从库中。

此时就配置完成了。在主库创建一个数据库,从库就会跟着创建一个数据库.

那要是主库挂了会怎么样?

这时IO线程处于重连状态,等待主库恢复运行.

主库恢复之后,它的日志表名变了,此时需要重新配置从库,不然从库使用的还是之前的错误日志表.

分库分表

大型互联网系统中,单台MySQL的存储容量无法满足需求,这时就需要扩容.

我们通过多台实例进行扩容,可以将数据分散,让多台主机共同保存数据.

那么如何进行拆分?

  • 垂直拆分:将数据库中的所有表,按照业务功能拆分到各个数据库中,而对于一张表,也可以通过外键之类的机制,将其拆分成多个表.

  • 水平拆分:水平拆分针对的是数据,不是表.让多个具有相同表的数据库协同存放一部分数据,相当于把数据分散到各个节点上.

实现这样的拆分操作,目前已经有一些解决方案了,比如mycat(数据库中间件,相当于挂了一层代理,再通过mycat进行分库分表操作数据库,只需要连接就能使用)或者Sharding JDBC(应用程序中字节对sql语句进行解析,然后转换成分库分表操作,需要自己编写一些逻辑代码),这里以Sharding JDBC为例!

Sharding JDBC

Sharding-JDBC 它定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

  • 适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
  • 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。

分库实现

具体实现水平拆分步骤如下:

  1. 新建一个spring boot项目.先导入依赖:
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> <version>5.1.0</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
  1. 编写配置文件
spring: shardingsphere: datasource: # 有几个数据源,就写几个,名称+数字的形式 names: ds0,ds1 # 每个数据源的具体配置 ds0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/yyds?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC username: root password: 123456 ds1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/yyds?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC username: root password: 123456
  1. 编写实体类和Mapper接口
@AllArgsConstructor @Data public class User { int id; String name; String password; }
@Mapper public interface UserMapper { @Select("select * from user where id = #{id}") User getUserById(int id); @Insert("insert into user (id, name, password) values (#{id}, #{name}, #{password})") int addUser(User user); }

这些都是常规操作,编写代码的关注点依然放在业务上.

现在需要编写配置文件,告诉Sharding JDBC要如何进行分片.(现在是两个数据库都有user表,我们的目标是将用户信息分别存放在这两个数据库中)

spring: shardingsphere: rules: sharding: tables: # 这里填写表名,程序中对这张表的所有操作 都会采用下面的路由方案 user: # 实际的路由数据节点,我们要分两个库,每个库一个表,所以是两个数据节点,格式是 数据源名称.表名 # 也可以使用表达式的方式来写,比如:ds$->{0..1}.user actual-data-nodes: ds0.user,ds1.user # 分库策略配置 database-strategy: # 这里选择标准的分库策略,也可以配置复杂的分库策略,具体可以参考官方文档 standard: # 参与分片运算的字段,通常是主键,下面的算法会根据这个字段的值来决定路由到哪个库 sharding-column: id # 选择分片算法,下面我们会自定义一个分片算法,命名为my-alg sharding-algorithm-name: my-alg sharding-algorithms: # 自定义的分片算法,命名为my-alg my-alg: # 算法类型(更多类型可以查询官方文档),这里选择MOD算法,MOD算法会根据分片字段的值对分片数量根据2取模来决定路由到哪个库 type: MOD props: shard-count: 2 props: # 开启SQL日志输出,方便我们观察SQL路由的情况 sql-show: true

这时就完成分库了,然后接可以进行业务开发了.

分表实现和查询

假如数据库中有test_01 和test_02两张表,表结构一样.我们希望能根据id取模运算的结果分别放到这两个不同的表中.首先需要明白两个概念:什么是逻辑表,什么是真实表

  • 逻辑表:相同结构的水平拆分数据库(表)的逻辑名称,是sql中表的逻辑标识,例如:订单数据根据主键拆分为10张表,分别是t_order_0到t_order_9,他们的逻辑表名就是t_order
  • 真实表:真实存在的表,就是上面的t_order_0到t_order_9

实现的时候,不用修改任何业务逻辑代码,只需要做相应的配置即可:

spring: shardingsphere: rules: sharding: tables: test: actual-data-nodes: ds0.test$->{0..1} # 配置分表策略 table-strategy: standard: sharding-column: id sharding-algorithm-name: my-alg sharding-algorithms: my-alg: # INLINE方式,自定义表达式来决定路由到哪个库,表达式中可以使用分片字段的值来进行计算 type: INLINE props: algorithm-expression: test$->{id % 2} # 查询也可以根据分片策略来进行,如果使用的是范围查询,依然会进行全量查询,这里先关闭 allow-range-query-with-inline-sharding: false

查询的时候,如果是根据id获取一行数据,实际上是去两张表里面查.

如果是范围查询,也就是返回结果是一个list集合的查询,需要配置allow-range-query-with-inline-sharding: true实际执行的sql是把两张表的查询结果union all起来,比如:

select * from test where id >10 -- 就是执行下面的sql select * from test_0 where id >10 union all select * from test_1 where id >10

分布式序列算法

在复杂分布式系统中,特别是微服务架构中,需要对大量数据和消息进行唯一标识.随着数据增多,分库分表成为常见方案,对数据分库分表后需要有一个唯一id来标识一条数据或消息(如订单号,事件编号等),此时需要一个能够生成全局唯一id的算法。这个id有以下要求:

  • 必须全局唯一
  • 尽可能保持有效,这样会提升索引的查询效率

满足以上需求的方案有:

  1. uuid:是一组32位数的16禁止数字随机构成,全局唯一 但无需。
  2. 雪花算法(Snowflake):生成一个64bit大小的整型id,需要使用Long类型。int类型装不下

雪花算法虽然具备了唯一性和有序性,但是依然有缺点,第一就是时间问题,如果机器时间出现倒退,那么就会导致生成重复的id,并且节点容量只有1024个,如果是超大规模集群,也存在隐患。

这里让Sharding JDBC用雪花算法为我们生成主键:

  1. 先把表中的主键字段类型改为bigint
  2. 修改配置文件,添加对应配置:
spring: shardingsphere: rules: sharding: tables: user: actual-data-nodes: ds0.user,ds1.user # 分库策略配置 database-strategy: # 这里选择标准的分库策略,也可以配置复杂的分库策略,具体可以参考官方文档 standard: # 参与分片运算的字段,通常是主键,下面的算法会根据这个字段的值来决定路由到哪个库 sharding-column: id # 选择分片算法,下面我们会自定义一个分片算法,命名为my-alg sharding-algorithm-name: my-alg key-generate-strategy: column: id key-generator-name: my-gen key-generators: # 自定义的主键生成算法,命名为my-gen my-gen: # 算法类型,这里选择SNOWFLAKE算法,SNOWFLAKE算法会生成全局唯一的ID,适合分布式环境 type: SNOWFLAKE props: # SNOWFLAKE算法需要配置一个worker-id,通常是一个唯一的数字,可以根据实际情况来设置,确保在分布式环境中不同的实例有不同的worker-id worker-id: 666 sharding-algorithms: # 自定义的分片算法,命名为my-alg my-alg: # 算法类型,这里选择MOD算法,MOD算法会根据分片字段的值对分片数量取模来决定路由到哪个库 type: MOD props: shard-count: 2 props: # 开启SQL日志输出,方便我们观察SQL路由的情况 sql-show: true

此时就完成了主键生成策略设置

读写分离

之前实现的MySQL主从复制模式,我们可以将主库作为写操作,从库作为只读操作

在实现了主从复制模式的基础上进行配置:

  1. 在从库的配置文件中,设置 read-only =1,这样从库就只能读数据了。

然后重启从库

  1. 配置Sharding JDBC
spring: shardingsphere: rules: # 配置读写分离 readwrite-splitting: data-sources: #名称随便写 user-db: type: static props: # 配置写库,只能写一个 write-data-source-name: ds0 # 配置读库,可以配置多个,逗号分隔 read-data-source-names: ds1 load-balancer-name: my-load load-balancers: # 自定义的负载均衡算法,命名为my-load my-load: type: round_robin
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 5:33:04

涡轮流量计选型指南:精准匹配工况需求的关键要素

近年来&#xff0c;随着工业自动化水平的不断提升和能源结构的持续优化&#xff0c;流量测量在石油、化工、天然气、电力及环境监测等领域的战略地位日益凸显。根据行业研究数据显示&#xff0c;2025年全球涡轮气体流量计市场规模约为12.3亿美元&#xff0c;预计将以约6.35%的年…

作者头像 李华
网站建设 2026/7/2 5:30:11

Java毕设选题推荐:基于 SpringBoot 的应急物资库存监控预警系统的设计与实现 基于 SpringBoot 的公共应急物资出入库溯源系【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/7/2 5:29:45

ICM-42688-P与PIC18F87K22在运动控制中的高效应用

1. ICM-42688-P与PIC18F87K22的黄金组合解析在工业级运动传感与控制领域&#xff0c;ICM-42688-P六轴MEMS惯性测量单元(IMU)与PIC18F87K22微控制器的组合正在成为高性价比解决方案的代名词。这套组合拳的独特之处在于&#xff1a;ICM-42688-P提供4000dps的陀螺仪量程和16g的加速…

作者头像 李华
网站建设 2026/7/2 5:27:59

AI大模型智能体开发:从原理到实战

1. 为什么现在每个人都需要掌握AI大模型智能体开发三年前我第一次接触GPT-3时&#xff0c;完全没想到大模型会以如此迅猛的速度改变整个技术生态。现在回头看&#xff0c;那些只会调用API的开发者已经明显落后了——真正有价值的是能够构建自主智能体的全栈开发者。这就像移动互…

作者头像 李华