5 快速入门分表分库
下面我们结合 Springboot + mybatisplus 快速搭建一个分库分表案例。
1、准备工作
先做准备工作,创建两个数据库 ds-0、ds-1,两个库中分别建表 t_order_0、t_order_1、t_order_2、t_order_item_0、t_order_item_1、t_order_item_2,t_config,方便后边验证广播表、绑定表的场景。
表结构如下:
t_order_0 订单表
CREATE TABLE `t_order_0` ( `order_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 (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
t_order_0 与 t_order_item_0 互为关联表
CREATE TABLE `t_order_item_0` ( `item_id` bigint(100) NOT NULL, `order_no` varchar(200) NOT NULL, `item_name` varchar(50) DEFAULT NULL, `price` decimal(10,2) DEFAULT NULL, PRIMARY KEY (`item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
广播表 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;
ShardingSphere 提供了4种分片配置方式:
Java 代码配置
Yaml 、properties 配置
Spring 命名空间配置
Spring Boot配置
为让代码看上去更简洁和直观,后边统一使用 properties 配置的方式,引入 shardingsphere 对应的 sharding-jdbc-spring-boot-starter 和 sharding-core-common 包,版本统一用的 4.0.0-RC1。
2、分片配置
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.0.0-RC1</version> </dependency> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-core-common</artifactId> <version>4.0.0-RC1</version> </dependency>
准备工作做完( mybatis 搭建就不赘述了),接下来我们逐一解读分片配置信息。
我们首先定义两个数据源 ds-0、ds-1,并分别加上数据源的基础信息。
# 定义两个全局数据源spring.shardingsphere.datasource.names=ds-0,ds-1 # 配置数据源 ds-0spring.shardingsphere.datasource. ds-0.type=com.alibaba.druid.pool.DruidDataSourcespring.shardingsphere.datasource. ds-0.driverClassName=com.mysql.jdbc.Driverspring.shardingsphere.datasource. ds-0.url=jdbc:mysql://127.0.0.1:3306/ds-0?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMTspring.shardingsphere.datasource.ds-0.username=rootspring.shardingsphere.datasource.ds-0.password=root # 配置数据源 ds-1spring.shardingsphere.datasource. ds-1.type=com.alibaba.druid.pool.DruidDataSourcespring.shardingsphere.datasource. ds-1.driverClassName=com.mysql.jdbc.Driverspring.shardingsphere.datasource.ds-1.url=jdbc:mysql://127.0.0.1:3306/ds-1?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMTspring.shardingsphere.datasource.ds-1.username=rootspring.shardingsphere.datasource.ds-1.password=root
配置完数据源接下来为表添加分库和分表策略,使用 sharding-jdbc 做分库分表需要我们为每一个表单独设置分片规则。
# 配置分片表 t_order # 指定真实数据节点 spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds-$->{0..1}.t_order_$->{0..2}
actual-data-nodes 属性指定分片的真实数据节点,$是一个占位符,{0…1}表示实际拆分的数据库表数量。
ds-$->{0..1}.t_order_$->{0..2} 表达式相当于 6个数据节点
ds-0.t_order_0
ds-0.t_order_1
ds-0.t_order_2
ds-1.t_order_0
ds-1.t_order_1
ds-1.t_order_2
### 分库策略 # 分库分片健 spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column=order_id # 分库分片算法 spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression=ds-$->{order_id % 2}
为表设置分库策略,上边讲了 sharding-jdbc 它提供了四种分片策略,为快速搭建我们先以最简单的行内表达式分片策略来实现,在下一篇会介绍四种分片策略的详细用法和使用场景。
database-strategy.inline.sharding-column 属性中 database-strategy 为分库策略,inline 为具体的分片策略,sharding-column 代表分片健。
database-strategy.inline.algorithm-expression 是当前策略下具体的分片算法,ds-$->{order_id % 2} 表达式意思是 对 order_id字段进行取模分库,2 代表分片库的个数,不同的策略对应不同的算法,这里也可以是我们自定义的分片算法类。
# 分表策略# 分表分片健spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id# 分表算法spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 3}# 自增主键字段spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id# 自增主键ID 生成方案spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
分表策略 和 分库策略 的配置比较相似,不同的是分表可以通过 key-generator.column 和 key-generator.type 设置自增主键以及指定自增主键的生成方案,目前内置了SNOWFLAKE 和 UUID 两种方式,还能自定义的主键生成算法类,后续会详细的讲解。
# 配置广播表spring.shardingsphere.sharding.broadcast-tables=t_config
必须按相同分片健进行分片的表才能互为成绑定表,在联合查询时就能避免出现笛卡尔积查询。
# 配置广播表spring.shardingsphere.sharding.broadcast-tables=t_config
广播表,开启 SQL解析日志,能清晰的看到 SQL分片解析的过程
# 是否开启 SQL解析日志 spring.shardingsphere.props.sql.show=true
3、验证分片
分片配置完以后我们无需在修改业务代码了,直接执行业务逻辑的增、删、改、查即可,接下来验证一下分片的效果。
我们同时向 t_order、t_order_item 表插入 5条订单记录,并不给定主键 order_id ,item_id字段值。
public String insertOrder() { for (int i = 0; i < 4; i++) { TOrder order = new TOrder(); order.setOrderNo("A000" + i); order.setCreateName("订单 " + i); order.setPrice(new BigDecimal("" + i)); orderRepository.insert(order); TOrderItem orderItem = new TOrderItem(); orderItem.setOrderId(order.getOrderId()); orderItem.setOrderNo("A000" + i); orderItem.setItemName("服务项目" + i); orderItem.setPrice(new BigDecimal("" + i)); orderItemRepository.insert(orderItem); } return "success"; }
看到订单记录被成功分散到了不同的库表中, order_id 字段也自动生成了主键ID,基础的分片功能就完成了。
那向广播表 t_config 中插入一条数据会是什么效果呢?
public String config() { TConfig tConfig = new TConfig(); tConfig.setRemark("我是广播表"); tConfig.setCreateTime(new Date()); tConfig.setLastModifyTime(new Date()); configRepository.insert(tConfig); return "success"; }
发现所有库中 t_config 表都执行了这条SQL,广播表和 MQ广播订阅的模式很相似,所有订阅的客户端都会收到同一条消息。
简单SQL操作验证没问通,接下来在试试复杂一点的联合查询,前边我们已经把 t_order、t_order_item 表设为绑定表,直接联表查询执行一下。
通过控制台日志发现,逻辑表SQL 经过解析以后,只对 t_order_0 和 t_order_item_0 表进行了关联产生一条SQL。
那如果不互为绑定表又会是什么情况呢?去掉 spring.shardingsphere.sharding.binding-tables试一下。
发现控制台解析出了 3条真实表SQL,而去掉 order_id 作为查询条件再次执行后,结果解析出了 9条SQL,进行了笛卡尔积查询。所以相比之下绑定表的优点就不言而喻了。
6 快速入门读写分离
(1)在Sharding-JDBC规则中修改
# 增加数据源s0,使用上面主从同步配置的从库。 spring.shardingsphere.datasource.names = m0,m1,m2,s0 ... spring.shardingsphere.datasource.s0.type = com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.s0.driver‐class‐name = com.mysql.jdbc.Driver spring.shardingsphere.datasource.s0.url = jdbc:mysql://localhost:3307/user_db?useUnicode=true spring.shardingsphere.datasource.s0.username = root spring.shardingsphere.datasource.s0.password = root .... # 主库从库逻辑数据源定义 ds0为user_db spring.shardingsphere.sharding.master‐slave‐rules.ds0.master‐data‐source‐name=m0 spring.shardingsphere.sharding.master‐slave‐rules.ds0.slave‐data‐source‐names=s0 # t_user分表策略,固定分配至ds0的t_user真实表 spring.shardingsphere.sharding.tables.t_user.actual‐data‐nodes = ds0.t_user ....
(2)测试
执行testInsertUser单元测试:
通过日志可以看出,所有写操作落入m0数据源。
执行testSelectUserbyIds单元测试:
通过日志可以看出,所有读操作落入s0数据源,达到目标。