前言
使用ShardingSphere分库分表之前,先介绍一下定义及流程,这样咱们下边的每一个配置都可以做到心里有数,另外在配置过程中会出现很多意外报错,配置中都会提到的。
概念、流程都明白的可以直接跳到最后看完整配置。
首先说一下分片的类型,可以分为:分库、分表、分库分表
- 分库
根据官方定义理解如下,可以看到下边截图,有两个库,每个库里有相同的3个表
- 分表
针对表进行分片,可以是单表,可以是关联表(比如order和order_item)
- 分库分表
将整表水平切分成多个分表,然后将这些分表分布到不同的库中。
当然,数据节点的分布方式又可以分成两种方式:均匀分布的数据节点、自定义的数据节点
均匀分布的数据节点
自定义的数据节点
演示案例
shardingsphere版本依赖信息
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.1.1</version>
</dependency>
其他主要依赖信息
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.1.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--JWT-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.11.0</version>
</dependency>
单库分表演示
-
准备数据库表
-
实体类
-
配置讲解
rules:
# 步骤:设置分片节点(一个整表分为了多少个分表)->分片规则(根据主键的分片算法,这样才能知道数据存取位置)->主键生成规则(uuid或者雪花算法SNOWFLAKE,可以不配置,不配置也可以)
sharding:
tables:
# 配置cl_user的分表的规则
cl_user:
# 拥有几个分片表0-3,表达式参考 h ttps://shardingsphere.apache.org/document/current/cn/features/sharding/concept/inline-expression/
actual-data-nodes: demo.cl_user_$->{0..3}
table-strategy:
standard:
sharding-column: id
sharding-algorithm-name: table-inline
# 配置分片算法
sharding-algorithms:
table-inline:
# 算法类型 参考 https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding/
type: INLINE
props:
algorithm-expression: cl_user_$->{id % 4}
这里会出现三个常见问题
-
分片算法跟主键不对应得问题(Inline sharding algorithms expression
xxx
and sharding columnxx
not mat)
原因是因为采用INLINE算法,然后你的注解可能是字符串类型,将类型改成Long或者Integer即可。 -
插入语句不支持分片表路由到多个数据节点(Insert statement does not support sharding table routing to multiple data nodes)
原因是实体类中,主键没有标识出来,加上标识注解即可,比如mybatis就用@TableId注解即可。
-
sharding-algorithms配置项不加载问题【最难定位的错误】
这个问题可能会报Route table null does not exist【INLINE算法】或者by zero【HASH_MOD算法】,原因就是配置没加载,因为项目中用了shiro,shiro中注入了userservice,ShardingSphere有引来了shiro得filter,所以会引发循环依赖,使用@lazy注解在你的service注入上。
这里,因为我的分片主键id是string,所以需要换成其他算法,选了(哈希取模分片算法)HASH_MOD,原因一是会报算法和主键不匹配的错,另一个原因是发现用(INLINE+cl_user_$->{id % 4}),每次添加新数据时,因为id生成的是19位的Long数据,取模之后大部分得到的结果都是1,2号表插入,反正我插入了几十条,算出来的都是1,2号表,0和3基本一条都没插入,为了平均和简单,所以直接选了HASH_MOD,测试还算是比较平均的插入到每张表了。
# 配置分片算法
sharding-algorithms:
table-inline:
# 算法类型 参考 https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding/
type: HASH_MOD
props:
sharding-count: 4 # 分片数量,自定义根据实际的分片
- 完整代码
common: &common
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
initial-size: 5
min-idle: 5
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
#Oracle需要打开注释
#validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,slf4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
wall:
multi-statement-allow: true
spring:
autoconfigure:
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
datasource:
druid:
stat-view-servlet:
enabled: true
loginUsername: admin
loginPassword: 123456
allow:
web-stat-filter:
enabled: true
shardingsphere:
props:
# 是否在日志中打印 SQL 更多属性参考->https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/props/
sql-show: true
datasource:
names: slave1
slave1:
url: jdbc:mysql://192.168.150.129:3306/test_data?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
<<: *common
rules:
# 步骤:设置分片节点(一个整表分为了多少个分表)->分片规则(根据主键的分片算法,这样才能知道数据存取位置)->主键生成规则(uuid或者雪花算法SNOWFLAKE)
sharding:
tables:
# 配置cl_user的分表的规则
cl_user:
# 拥有几个分片表0-3,表达式参考 https://shardingsphere.apache.org/document/current/cn/features/sharding/concept/inline-expression/
actual-data-nodes: slave1.cl_user_$->{0..3}
table-strategy:
standard:
sharding-column: id
sharding-algorithm-name: table-inline
# key-generate-strategy:
# column: id
# key-generator-name: snowflake
# 配置分片算法
sharding-algorithms:
table-inline:
# 算法类型 参考 https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding/
type: HASH_MOD
props:
sharding-count: 4
# key-generators:
# snowflake:
# type: SNOWFLAKE
redis:
open: false # 是否开启redis缓存 true开启 false关闭
database: 1
host: 127.0.0.1
port: 6379
password: # 密码(默认为空)
timeout: 6000ms # 连接超时时长(毫秒)
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
分布式主键算法策略注释了,因为我发现这个版本配置和不配置效果一样。
分库
只改yml配置文件即可,增加slave0库
datasource:
names: slave1,slave0
slave1:
url: jdbc:mysql://192.168.150.129:3306/test_data?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
<<: *common
slave0:
url: jdbc:mysql://192.168.150.132:3306/test_data?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
<<: *common
rules:
# 步骤:设置分片节点(一个整表分为了多少个分表)->分片规则(根据主键的分片算法,这样才能知道数据存取位置)->主键生成规则(uuid或者雪花算法SNOWFLAKE)
sharding:
tables:
# 配置cl_user的分表的规则
cl_user:
# 拥有几个分片表0-3,表达式参考 https://shardingsphere.apache.org/document/current/cn/features/sharding/concept/inline-expression/
actual-data-nodes: slave$->{0..1}.cl_user_$->{0..3}
table-strategy:
standard:
sharding-column: id
sharding-algorithm-name: table-inline
# 和下边的默认分库配置(default-database-strategy)任选一个即可
# database-strategy:
# standard:
# sharding-column: id
# sharding-algorithm-name: database-inline
# 配置分片算法
sharding-algorithms:
# 分表算法
table-inline:
# 算法类型 参考 https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding/
type: HASH_MOD
props:
sharding-count: 4
# 分库算法
database-inline:
type: HASH_MOD
props:
sharding-count: 2
default-database-strategy:
standard:
sharding-column: id
sharding-algorithm-name: database-inline
这里增加了两个配置一个分库算法database-inline,一个分库算法引用配置default-database-strategy,另外,提醒一下大家,分库命名最好都从0开始,比如,最开始我用的是slave1,slave2,结果就会一直报数据库路由找不到的错误,原因就是取模算法中会取到0,所以找0号库找不到。
分库分表
因为表分布在不同的库中,所以对比算法要求就高了,单纯的内置算法就不足以满足需求,所以需要自定义算法,这里我将上边的slave0和slave1互换了名字,正好对应分表0,1和2,3,方便理解,另外,提一下,行表达式可以写三元表达式,比如:
好了,话不多说,正式开始
rules:
# 步骤:设置分片节点(一个整表分为了多少个分表)->分片规则(根据主键的分片算法,这样才能知道数据存取位置)->主键生成规则(uuid或者雪花算法SNOWFLAKE)
sharding:
tables:
# 配置cl_user的分表的规则
cl_user:
# 拥有几个分片表0-3,表达式参考 https://shardingsphere.apache.org/document/current/cn/features/sharding/concept/inline-expression/
actual-data-nodes: slave0.cl_user_$->{0..1},slave1.cl_user_$->{2..3}
table-strategy:
standard:
sharding-column: id
sharding-algorithm-name: table-myself
# 配置分片算法
sharding-algorithms:
# 分表算法
table-myself:
type: MYSELF
props:
#数据库和表的对应关系,自定义
databases-tables-relevance: "{0:[0,1],1:[2,3]}"
# 分库算法
database-inline:
type: INLINE
props:
algorithm-expression: slave$->{id % 2}
default-database-strategy:
standard:
sharding-column: id
sharding-algorithm-name: database-inline
这里我用了自定义方法table-myself.
规则详情:根据分库算法算出来0号库还是1号库,然后再根据库来随机选出来库所对应的表。
当然,这些算法是根据你自己的需求自己写的,我这里举个例子,详细配置自定义分片规则,请跳这里
自定义分片算法
好啦,读写分离+分库分表,读写分离,自定义算法等等,可以去我的个人主页一一查看。