MySQL 使用 Sharding-jdbc 分库分表

一、为什么要分库分表

如果一个网站业务快速发展,那这个网站流量也会增加,数据的压力也会随之而来,比如电商系统来说双十一大促对订单数据压力很大,Tps十几万并发量,如果传统的架构(一主多从),主库容量肯定无法满足这么高的Tps,业务越来越大,单表数据超出了数据库支持的容量,持久化磁盘IO,传统的数据库性能瓶颈,产品经理业务·必须做,改变程序,数据库刀子切分优化。数据库连接数不够需要分库,表的数据量大,优化后查询性能还是很低,需要分。

不管是 IO 瓶颈,还是 CPU
瓶颈,最终都会导致数据库的活跃连接数增加,进而逼近甚至达到数据库可承载活跃连接数的阈值。在业务服务来看就是,可用数据库连接少甚至无连接可用,那导致的问题就可以想象了吧:并发量、吞吐量、崩溃等等情况。

二、技术选型

1.大体分为两个方向

应用层依赖类中间件、中间层代理类中间件。
1)mycat是一个中间件的第三方应用,sharding-jdbc是一个jar包

2)使用mycat时不需要改代码,而使用sharding-jdbc时需要修改代码
分库依据 跳转https://zhuanlan.zhihu.com/p/375951738

三、sharding

这里就详细讲述Sharding MyCat就不过多描述了

1、基本简介

Sharding-JDBC最早是当当网外部应用的一款分库分表框架,到2017年的时候才开始对外开源,这几年在大量社区贡献者的一直迭代下,性能也逐步欠缺,现已更名为 ShardingSphere,2020年4⽉16⽇正式成为 Apache 软件基⾦会的顶级项⽬。

随着版本的一直更迭 ShardingSphere 的外围性能也变得多元化起来。从最开始 Sharding-JDBC 1.0 版本只有数据分片,到 Sharding-JDBC 2.0 版本开始提供数据库治理(注册核心、配置核心等等),再到 Sharding-JDBC 3.0版本又加分布式事务 ( Atomikos、Narayana、Bitronix、Seata)

当初的 ShardingSphere 不单单是指某个框架而是一个生态圈,这个生态圈 Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar 这三款开源的分布式数据库中间件解决方案所形成,ShardingSphere 的前身就是 Sharding-JDBC,所以它是整个框架中最为经典、成熟的组件,咱们先从 Sharding-JDBC 框架动手学习分库分表。

sharding-sphere(分片球体) 由三部分组成:sharding-jdbc、sharding-proxy、sharding-Sidecar

sharding-jdbc:被定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务,以 jar 包形式使用。(本文着重介绍其使用)
sharding-proxy:被定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。
sharding-sidecar:被定位为 Kubernetes 或 Mesos 的云原生数据库代理,以 DaemonSet 的形式代理所有对数据库的访问,此模块目前还在规划中

2、基本概念

在开始 Sharding-JDBC分库分表具体实战之前,咱们有必要先理解分库分表的一些基本概念。

分片:
个别咱们在提到分库分表的时候,大多是以程度切分模式(程度分库、分表)为根底来说的,数据分片将本来一张数据量较大的表 t_order 拆分生成数个表构造完全一致的小数据量表 t_order_0、t_order_1、···、t_order_n,每张表只存储原大表中的一部分数据,当执行一条SQL时会通过 分库策略、分片策略 将数据扩散到不同的数据库、表内。

数据节点:
数据节点是分库分表中一个不可再分的最小数据单元(表),它由数据源名称和数据表组成,例如上图中order_db_1.t_order_0、order_db_2.t_order_1 就示意一个数据节点。

逻辑表:
逻辑表是指一组具备雷同逻辑和数据结构表的总称。比方咱们将订单表t_order 拆分成 t_order_0 ··· t_order_9 等 10张表。此时咱们会发现分库分表当前数据库中已不在有 t_order 这张表,取而代之的是 t_order_n,但咱们在代码中写 SQL 仍然按 t_order 来写。此时 t_order 就是这些拆分表的逻辑表。

实在表:
实在表也就是上边提到的 t_order_n 数据库中实在存在的物理表。
用于分片的数据库字段。咱们将 t_order 表分片当前,当执行一条SQL时,通过对字段 order_id 取模的形式来决定,这条数据该在哪个数据库中的哪个表中执行,此时 order_id 字段就是 t_order 表的分片健。
这样以来同一个订单的相干数据就会存在同一个数据库表中,大幅晋升数据检索的性能,不仅如此 sharding-jdbc 还反对依据多个字段作为分片健进行分片。

分片算法
上边咱们提到能够用分片健取模的规定分片,但这只是比较简单的一种,在理论开发中咱们还心愿用 >=、<=、>、<、BETWEEN 和 IN 等条件作为分片规定,自定义分片逻辑,这时就须要用到分片策略与分片算法。

从执行 SQL 的角度来看,分库分表能够看作是一种路由机制,把 SQL 语句路由到咱们冀望的数据库或数据表中并获取数据,分片算法能够了解成一种路由规定。分片策略只是形象出的概念,它是由分片算法和分片健组合而成,分片算法做具体的数据分片逻辑。

分库、分表的分片策略配置是绝对独立的,能够各自应用不同的策略与算法,每种策略中能够是多个分片算法的组合,每个分片算法能够对多个分片健做逻辑判断。sharding-jdbc 并没有间接提供分片算法的实现,须要开发者依据业务自行实现。

sharding-jdbc 提供了4种分片算法
1、准确分片算法
准确分片算法(PreciseShardingAlgorithm)用于单个字段作为分片键,SQL中有 = 与 IN 等条件的分片,须要在规范分片策略(StandardShardingStrategy )下应用。

2、范畴分片算法
范畴分片算法(RangeShardingAlgorithm)用于单个字段作为分片键,SQL中有 BETWEEN AND、>、<、>=、<= 等条件的分片,须要在规范分片策略(StandardShardingStrategy )下应用。

3、复合分片算法
复合分片算法(ComplexKeysShardingAlgorithm)用于多个字段作为分片键的分片操作,同时获取到多个分片健的值,依据多个字段解决业务逻辑。须要在复合分片策略(ComplexShardingStrategy )下应用。

4、Hint分片算法
Hint分片算法(HintShardingAlgorithm)稍有不同,上边的算法中咱们都是解析SQL 语句提取分片键,并设置分片策略进行分片。但有些时候咱们并没有应用任何的分片键和分片策略,可还想将 SQL 路由到指标数据库和表,就须要通过手动干涉指定SQL的指标数据库和表信息,这也叫强制路由。

分片策略

分片策略
上边讲分片算法的时候曾经说过,分片策略是一种形象的概念,理论分片操作的是由分片算法和分片健来实现的。

1、规范分片策略
规范分片策略实用于单分片键,此策略反对 PreciseShardingAlgorithm 和 RangeShardingAlgorithm 两个分片算法。

其中 PreciseShardingAlgorithm 是必选的,用于解决 = 和 IN 的分片。RangeShardingAlgorithm 是可选的,用于解决BETWEEN AND, >, <,>=,<= 条件分片,如果不配置RangeShardingAlgorithm,SQL中的条件等将依照全库路由解决。

2、复合分片策略
复合分片策略,同样反对对 SQL语句中的 =,>, <, >=, <=,IN和 BETWEEN AND 的分片操作。不同的是它反对多分片键,具体调配片细节齐全由利用开发者实现。

3、行表达式分片策略
行表达式分片策略,反对对 SQL语句中的 = 和 IN 的分片操作,但只反对单分片键。这种策略通常用于简略的分片,不须要自定义分片算法,能够间接在配置文件中接着写规定。

t_order_$->{t_order_id % 4} 代表 t_order 对其字段 t_order_id取模,拆分成4张表,而表名别离是t_order_0 到 t_order_3。

4、Hint分片策略
Hint分片策略,对应上边的Hint分片算法,通过指定分片健而非从 SQL中提取分片健的形式进行分片的策略。

分布式主键
数据分⽚后,不同数据节点⽣成全局唯⼀主键是⾮常棘⼿的问题,同⼀个逻辑表(t_order)内的不同实在表(t_order_n)之间的⾃增键因为⽆法相互感知而产⽣反复主键。
只管可通过设置⾃增主键 初始值 和 步⻓ 的⽅式防止ID碰撞,但这样会使保护老本加大,乏完整性和可扩展性。如果后去须要减少分片表的数量,要逐个批改分片表的步长,运维老本十分高,所以不倡议这种形式。
为了让上手更加简略,ApacheShardingSphere 内置了UUID、SNOWFLAKE 两种分布式主键⽣成器,默认使⽤雪花算法(snowflake)⽣成64bit的⻓整型数据。不仅如此它还抽离出分布式主键⽣成器的接口,⽅便咱们实现⾃定义的⾃增主键⽣成算法。

播送表
播送表:存在于所有的分片数据源中的表,表构造和表中的数据在每个数据库中均完全一致。个别是为字典表或者配置表 t_config,某个表一旦被配置为播送表,只有批改某个数据库的播送表,所有数据源中播送表的数据都会跟着同步。

绑定表
绑定表:那些分片规定统一的主表和子表。比方:t_order 订单表和 t_order_item 订单服务项目表,都是按 order_id 字段分片,因而两张表互为绑定表关系。那绑定表存在的意义是啥呢?
通常在咱们的业务中都会应用 t_order 和 t_order_item 等表进行多表联结查问,但因为分库分表当前这些表被拆分成N多个子表。如果不配置绑定表关系,会呈现笛卡尔积关联查问,将产生如下四条SQL。

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id 
SELECT * FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id 
SELECT * FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id 
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id 

而配置绑定表关系后再进行关联查问时,只有对应表分片规定统一产生的数据就会落到同一个库中,那么只需 t_order_0 和 t_order_item_0 表关联即可。

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id 
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id 

在关联查问时 t_order 它作为整个联结查问的主表。 所有相干的路由计算都只应用主表的策略,t_order_item 表的分片相干的计算也会应用 t_order 的条件,所以要保障绑定表之间的分片键要完全相同。

一张表通过分库分表后被拆分成多个子表,并扩散到不同的数据库中,在不批改原业务 SQL 的前提下,Sharding-JDBC 就必须对
SQL进行一些革新能力失常执行。

大抵的执行流程:SQL 解析 -> 执⾏器优化 -> SQL 路由 -> SQL 改写 -> SQL 执⾏ -> 后果归并
六步组成,一起瞅瞅每个步骤做了点什么。

SQL 解析
SQL解析过程分为词法解析和语法解析两步,比方下边这条查问用户订单的SQL,先用词法解析将SQL拆解成不可再分的原子单元。在依据不同数据库方言所提供的字典,将这些单元归类为关键字,表达式,变量或者操作符等类型。

SELECT order_no,price FROM t_order_ where user_id = 10086 and order_status > 0

接着语法解析会将拆分后的SQL转换为形象语法树,通过对形象语法树遍历,提炼出分片所需的上下文,上下文蕴含查问字段信息(Field)、表信息(Table)、查问条件(Condition)、排序信息(Order By)、分组信息(Group By)以及分页信息(Limit)等,并标记出 SQL中有可能须要改写的地位。

执⾏器优化
执⾏器优化对SQL分片条件进行优化,解决像关键字 OR这种影响性能的条件。

SQL 路由
SQL 路由通过解析分片上下文,匹配到用户配置的分片策略,并生成路由门路。简略点了解就是能够依据咱们配置的分片策略计算出 SQL该在哪个库的哪个表中执行,而SQL路由又依据有无分片健辨别出 分片路由 和 播送路由。

有分⽚键的路由叫分片路由,细分为间接路由、规范路由和笛卡尔积路由这3种类型。

规范路由
规范路由是最举荐也是最为常⽤的分⽚⽅式,它的适⽤范畴是不蕴含关联查问或仅蕴含绑定表之间关联查问的SQL。

当 SQL分片健的运算符为 = 时,路由后果将落⼊单库(表),当分⽚运算符是BETWEEN 或IN 等范畴时,路由后果则不⼀定落⼊唯⼀的库(表),因而⼀条逻辑SQL最终可能被拆分为多条⽤于执⾏的实在SQL。

SELECT * FROM t_order  where t_order_id in (1,2)

SQL路由解决后

SELECT * FROM t_order_0  where t_order_id in (1,2)
SELECT * FROM t_order_1  where t_order_id in (1,2)

间接路由
间接路由是通过应用 HintAPI 间接将 SQL路由到指定⾄库表的一种分⽚形式,而且间接路由能够⽤于分⽚键不在SQL中的场景,还能够执⾏包含⼦查问、⾃定义函数等简单状况的任意SQL。
比方依据 t_order_id字段为条件查问订单,此时心愿在不批改SQL的前提下,加上 user_id作为分片条件就能够应用间接路由。

笛卡尔积路由
笛卡尔路由是由⾮绑定表之间的关联查问产生的,查问性能较低尽量避免走此路由模式。

无分片路由又叫做播送路由,能够划分为全库表路由、全库路由、 全实例路由、单播路由和阻断路由这 5种类型。

全库表路由
全库表路由针对的是数据库 DQL和 DML,以及 DDL等操作,当咱们执行一条逻辑表 t_order SQL时,在所有分片库中对应的实在表 t_order_0 ··· t_order_n 内逐个执行。

全库路由
全库路由次要是对数据库层面的操作,比方数据库 SET 类型的数据库治理命令,以及 TCL 这样的事务管制语句。

对逻辑库设置 autocommit 属性后,所有对应的实在库中都执行该命令。

SET autocommit=0;

全实例路由
全实例路由是针对数据库实例的 DCL 操作(设置或更改数据库用户或角色权限),比方:创立一个用户 order ,这个命令将在所有的实在库实例中执行,以此确保 order 用户能够失常拜访每一个数据库实例。

CREATE USER [email protected] identified BY '程序员内点事';

单播路由
单播路由用来获取某一实在表信息,比方取得表的形容信息:

DESCRIBE t_order;
t_order 的实在表是 t_order_0 ···· t_order_n,他们的形容构造相齐全同,咱们只需在任意的实在表执行一次就能够。

阻断路由
⽤来屏蔽SQL对数据库的操作,例如:

USE order_db;
这个命令不会在实在数据库中执⾏,因为 ShardingSphere 采⽤的是逻辑 Schema(数据库的组织和构造) ⽅式,所以无需将切换数据库的命令发送⾄实在数据库中。

SQL 改写

将基于逻辑表开发的SQL改写成能够在实在数据库中能够正确执行的语句。比方查问 t_order 订单表,咱们理论开发中 SQL是按逻辑表
t_order 写的。

SELECT * FROM t_order 但分库分表当前实在数据库中 t_order 表就不存在了,而是被拆分成多个子表
t_order_n 扩散在不同的数据库内,还按原SQL执行显然是行不通的,这时须要将分表配置中的逻辑表名称改写为路由之后所获取的实在表名称。

SELECT * FROM t_order_n SQL执⾏ 将路由和改写后的实在 SQL
平安且高效发送到底层数据源执行。但这个过程并不是简略的将 SQL 通过JDBC
间接发送至数据源执行,而是均衡数据源连贯创立以及内存占用所产生的耗费,它会自动化的均衡资源管制与执行效率。

后果归并
将从各个数据节点获取的多数据后果集,合并成一个大的后果集并正确的返回至申请客户端,称为后果归并。而咱们SQL中的排序、分组、分页和聚合等语法,均是在归并后的后果集上进行操作的。

4、实例验证
下面咱们联合springboot2,mybatis_plus+druid+sharding-jdbc疾速搭建一个分库分表案例。
首先创建库的环境 两个库db_test0 db_test1
在这里插入图片描述

# 创建播送表 t_config   
CREATE TABLE `t_config` (
  `id` bigint(30) NOT NULL,
  `remark` varchar(50) CHARACTER SET utf8 DEFAULT NULL,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `last_modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

# 创建第一张订单表(依次创建多张)
CREATE TABLE `t_order_1` (
  `id` bigint(200) NOT NULL,
  `order_no` varchar(100) DEFAULT NULL,
  `create_name` varchar(50) DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

# 创建绑定表 (t_order_n 跟 t_order_item_n 之间关联查询)
# 跟t_order_n 对应 t_order_n   n个数相同
CREATE TABLE `t_order_item_1` (
  `id` bigint(100) NOT NULL,
  `order_no` varchar(200) DEFAULT NULL,
  `item_name` varchar(50) DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  `order_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;


### 然后在按照上面sql创建第二个数据库 结构相同(水平分库)

添加pom依赖

            <!-- Sharding-JDBC -->
            <dependency>
                <groupId>org.apache.shardingsphere</groupId>
                <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
                <version>4.0.0-RC1</version>
            </dependency>

添加配置文件 这个是完整的依赖根据需要自行修改

需要properties 类型的文件 可以去转换一下 https://www.toyaml.com/index.html

spring:
  shardingsphere:
    # 显示shardingsphere执行的sql
    props:
      sql:
        show: true
    datasource:
    #names 可以配置多个数据节点名  复数
      names: ds-0,ds-1
      ds-0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_test0?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true
        username: root
        password: password
        #初始化建立物理链接的个数
        initial-size: 5
        #最大连接池数量
        max-active: 10
        #最小连接池数量
        min-idle: 5
        #获取连接时最大等待时间,单位毫秒
        max-wait: 60000
        # 超过时间限制是否回收
        removeAbandoned: true
        # 当连接超过3分钟后会强制进行回收
        removeAbandonedTimeout: 180
        #打开PSCache,并且指定每个连接上PSCache的大小
        pool-prepared-statements: true
        max-pool-prepared-statement-per-connection-size: 20
        #间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
        time-between-eviction-runs-millis: 60000
        min-evictable-idle-time-millis: 300000
        max-evictable-idle-time-millis: 600000
        #用来检测连接是否有效的sql 必须是一个查询语句。mysql中为 select 'x', oracle中为 select 1 from dual
        validation-query: select 'x'
        # validation-query-timeout: 5000
        #申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
        test-on-borrow: false
        #归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
        test-on-return: false
        test-while-idle: true
        #通过connectProperties属性来打开mergeSql功能,慢SQL记录 超过5000毫秒
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
        #filters:  启用内置过滤器(第一个 stat必须,否则监控不到SQL) #配置多个英文逗号分隔(统计,sql注入)  stat:Druid内置提供一个StatFilter,用于统计监控信息。
        # wall:Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析。Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。
        filters: stat,wall
        #合并多个DruidDataSource的监控数据
        use-global-data-source-stat: false
        #配置stat-view-servlet
        stat-view-servlet:
          #允许开启监控
          enabled: true
          #监控面板路径
          url-pattern: /druid/*
      ds-1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_test1?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true
        username: root
        password: password
        #初始化建立物理链接的个数
        initial-size: 5
        #最大连接池数量
        max-active: 10
        #最小连接池数量
        min-idle: 5
        #获取连接时最大等待时间,单位毫秒
        max-wait: 60000
        # 超过时间限制是否回收
        removeAbandoned: true
        # 当连接超过3分钟后会强制进行回收
        removeAbandonedTimeout: 180
        #打开PSCache,并且指定每个连接上PSCache的大小
        pool-prepared-statements: true
        max-pool-prepared-statement-per-connection-size: 20
        #间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
        time-between-eviction-runs-millis: 60000
        min-evictable-idle-time-millis: 300000
        max-evictable-idle-time-millis: 600000
        #用来检测连接是否有效的sql 必须是一个查询语句。mysql中为 select 'x', oracle中为 select 1 from dual
        validation-query: select 'x'
        # validation-query-timeout: 5000
        #申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
        test-on-borrow: false
        #归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
        test-on-return: false
        test-while-idle: true
        #通过connectProperties属性来打开mergeSql功能,慢SQL记录
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
        #filters: #配置多个英文逗号分隔(统计,sql注入)
        filters: stat,wall
        #合并多个DruidDataSource的监控数据
        use-global-data-source-stat: false
        #配置stat-view-servlet
        stat-view-servlet:
          #允许开启监控
          enabled: true
          #监控面板路径
          url-pattern: /druid/*
    sharding:
      tables:
        # 配置分片表 可配置多个表 t_order key-generator:设置密钥生成uuid 生成主键Id  SNOWFLAKE:雪花
        t_order:
        # 设置id键 使用雪花算法生成
          key-generator:
            column: id
            type: SNOWFLAKE
#指定真实当前数据节点 使用行表达式上面有提到 $起到占位的作用->替换成后面的数值,灵活运动,跟数据库是对应的
          actual-data-nodes: ds-$->{
    
    0..1}.t_order_$->{
    
    1..2}
          ### 分库策略
          database-strategy:
            inline:
              #分库分片键
              sharding‐column: id
              #分库分片算法
              algorithm-expression: ds-$->{
    
    id % 2}
          # 分表策略
          table-strategy:
            inline:
              # 分表分片健
              sharding‐column: id
              # 分表算法
              algorithm-expression: t_order_$->{
    
    id % 3}
        # 配置分片表 t_order
        t_order_item:
          key-generator:
            column: id
            type: SNOWFLAKE
          #指定数据节点
          actual-data-nodes: ds-$->{
    
    0..1}.t_order_item_$->{
    
    1..2}
          ### 分库策略
          database-strategy:
            inline:
              #分库分片键
              sharding‐column: order_id
              #分库分片算法
              algorithm-expression: ds-$->{
    
    order_id % 2}
          # 分表策略
          table-strategy:
            inline:
              # 分表分片健
              sharding‐column: order_id
              # 分表算法
              algorithm-expression: t_order_item_$->{
    
    order_id % 3}

      # 绑定表关系
      binding-tables[0]: t_order,t_order_item
      # 配置播送表
      broadcast-tables: t_config
      binding-tables:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    # 允许bean定义重写
  main:
    allow-bean-definition-overriding: true

我使用的

spring:
  shardingsphere:
    # 显示shardingsphere执行的sql
    props:
      sql:
        show: true
    datasource:
      names: ds-0,ds-1
      ds-0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_test0?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true
        username: root
        password: root
        #初始化建立物理链接的个数
        initial-size: 5
        #最大连接池数量
        max-active: 10
        #最小连接池数量
        min-idle: 5
        #filters:  启用内置过滤器(第一个 stat必须,否则监控不到SQL) #配置多个英文逗号分隔(统计,sql注入)  stat:Druid内置提供一个StatFilter,用于统计监控信息。
        # wall:Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析。Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。
        filters: stat,wall
        #合并多个DruidDataSource的监控数据
        use-global-data-source-stat: false
        #配置stat-view-servlet
        stat-view-servlet:
          #允许开启监控
          enabled: true
          #监控面板路径
          url-pattern: /druid/*
      ds-1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_test1?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true
        username: root
        password: root
        #初始化建立物理链接的个数
        initial-size: 5
        #最大连接池数量
        max-active: 10
        #最小连接池数量
        min-idle: 5
        #获取连接时最大等待时间,单位毫秒
        max-wait: 60000
        #通过connectProperties属性来打开mergeSql功能,慢SQL记录
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
        #filters: #配置多个英文逗号分隔(统计,sql注入)
        filters: stat,wall
        #合并多个DruidDataSource的监控数据
        use-global-data-source-stat: false
        #配置stat-view-servlet
        stat-view-servlet:
          #允许开启监控
          enabled: true
          #监控面板路径
          url-pattern: /druid/*
    sharding:
      tables:
        # 配置分片表 可配置多个表 t_order key-generator:设置密钥生成uuid 生成主键Id  SNOWFLAKE:雪花
        t_order:
          key-generator:
            column: id
            type: SNOWFLAKE
          #指定当前数据节点 
          actual-data-nodes: ds-$->{
    
    0..1}.t_order_$->{
    
    1..2}
          ### 分库策略
          database-strategy:
            inline:
              #分库分片键
              sharding‐column: id
              #分库分片算法 要么ds-0  要么添加ds-1
              algorithm-expression: ds-$->{
    
    id % 2}
          # 分表策略
          table-strategy:
            inline:
              # 分表分片健
              sharding‐column: id
              # 分表算法
              algorithm-expression: t_order_$->{
    
    id % 2 + 1}
        # 配置分片表 t_order
        t_order_item:
          key-generator:
            column: id
            type: SNOWFLAKE
          #指定数据节点
          actual-data-nodes: ds-$->{
    
    0..1}.t_order_item_$->{
    
    1..2}
          ### 分库策略
          database-strategy:
            inline:
              #分库分片键
              sharding‐column: order_id
              #分库分片算法
              algorithm-expression: ds-$->{
    
    order_id % 2}
          # 分表策略
          table-strategy:
            inline:
              # 分表分片健
              sharding‐column: order_id
              # 分表算法
              algorithm-expression: t_order_item_$->{
    
    order_id % 2 + 1}

      # # 绑定表关系
      # binding-tables[0]: t_order,t_order_item
      broadcast-tables: t_config
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
  main:
    allow-bean-definition-overriding: true

四、测试

@Test
public void testSharding() {
    
    
    for (int i = 0; i < 10; i++) {
    
    
        TOrder order = new TOrder();
        order.setOrderNo("A000" + String.valueOf(i));
        order.setCreateName("订单" + i);
        order.setPrice(new BigDecimal(i));
        tOrderService.save(order);

        TOrderItem orderItem = new TOrderItem();
        orderItem.setOrderId(order.getId());
        orderItem.setOrderNo(order.getOrderNo());
        orderItem.setItemName("服务项目" + i);
        orderItem.setPrice(new BigDecimal("" + i));
        tOrderItemService.save(orderItem);
    }
}

在这里插入图片描述
在这里插入图片描述
看到订单记录被胜利扩散到了不同的库表中, order_id 字段也主动生成了主键ID,根底的分片性能就实现了。
那向播送表 t_config 中插入一条数据会是什么成果呢?

@Test
public void testShardingbrock() {
    
    
    TConfig tConfig = new TConfig();
    tConfig.setRemark("我是播送表");
    tConfig.setCreateTime(LocalDateTime.now());
    tConfig.setLastModifyTime(LocalDateTime.now());
    tConfigService.save(tConfig);
}

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_62812758/article/details/129361242