当业务的数据量暴增,单个数据库无法承载时,我们就需要扩容,此时就可以使用ShardingSphere的分库分表。
1、垂直拆分
数据库的垂直拆分:比如将业务拆分成多个微服务。
表的垂直拆分:比如将一个订单表里面既有订单信息,又有优惠券信息,我们就可以将它拆分成两个表。
2、水平拆分
简单的来说就是将数据分片存储。
SpringBoot整合ShardingSphere-JDBC实现分库分表
首先我们创建3个数据源:server-user,server-order0,server-order1
docker run -d \
-p 3301:3306 \
-v /yy/mysql/user/conf:/etc/mysql/conf.d \
-v /yy/mysql/user/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-user \
mysql:8.0.29
docker run -d \
-p 3310:3306 \
-v /yy/mysql/order0/conf:/etc/mysql/conf.d \
-v /yy/mysql/order0/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order0 \
mysql:8.0.29
docker run -d \
-p 3311:3306 \
-v /yy/mysql/order1/conf:/etc/mysql/conf.d \
-v /yy/mysql/order1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order1 \
mysql:8.0.29
在server-order0、server-order1的db_order数据库中分别创建两个表:
CREATE TABLE `t_order0` (
`id` BIGINT(20) UNSIGNED NOT NULL,
`order_no` VARCHAR(50),
`user_id` BIGINT(19) ,
`amount` DECIMAL(20,6) ,
PRIMARY KEY (`id`) USING BTREE
)
CREATE TABLE `t_order1` (
`id` BIGINT(20) UNSIGNED NOT NULL,
`order_no` VARCHAR(50),
`user_id` BIGINT(19),
`amount` DECIMAL(20,6),
PRIMARY KEY (`id`) USING BTREE
)
# 应用名称
spring.application.name=sharding-sph
spring.profiles.active=dev
spring.shardingsphere.mode.type=Memory
spring.shardingsphere.props.sql-show=true
# 配置真实数据源
spring.shardingsphere.datasource.names=server-user,server-order0,server-order1
# 配置第 1 个数据源
spring.shardingsphere.datasource.server-user.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-user.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-user.jdbc-url=jdbc:mysql://IP地址:3301/db_user?serverTimezone=UTC&characterEncoding=UTF-8
spring.shardingsphere.datasource.server-user.username=root
spring.shardingsphere.datasource.server-user.password=123456
# 配置第 2 个数据源
spring.shardingsphere.datasource.server-order0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-order0.jdbc-url=jdbc:mysql://IP地址:3310/db_order?serverTimezone=UTC&characterEncoding=UTF-8
spring.shardingsphere.datasource.server-order0.username=root
spring.shardingsphere.datasource.server-order0.password=123456
# 配置第 3 个数据源
spring.shardingsphere.datasource.server-order1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.server-order1.jdbc-url=jdbc:mysql://IP地址:3311/db_order?serverTimezone=UTC&characterEncoding=UTF-8
spring.shardingsphere.datasource.server-order1.username=root
spring.shardingsphere.datasource.server-order1.password=123456
#---------标准分片表配置-----------
spring.shardingsphere.rules.sharding.tables.t_user.actual-data-nodes=server-user.t_user
spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=server-order$->{0..1}.t_order$->{0..1}
# 分库策略,缺省表示使用默认分库策略,以下的分片策略只能选其一
# 分片算法配置---INLINE算法
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_inline_userId.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_inline_userId.props.algorithm-expression=server-order$->{user_id%2}
# 分库策略,缺省表示使用默认分库策略,以下的分片策略只能选其一
# 分片算法配置---MOD算法
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_mod.type=MOD
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_mod.props.sharding-count=2
# 分表策略,缺省表示使用默认分库策略,以下的分片策略只能选其一
# 分片算法配置---hashMod算法
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_hash_mod.type=HASH_MOD
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_hash_mod.props.sharding-count=2
# 分片列名称
##------分库策略
spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-column=user_id
spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-algorithm-name=alg_mod
# 分片列名称
##----分表策略
spring.shardingsphere.rules.sharding.tables.t_order.table-strategy.standard.sharding-column=order_no
spring.shardingsphere.rules.sharding.tables.t_order.table-strategy.standard.sharding-algorithm-name=alg_hash_mod
#-----------分布式序列策略配置
# 分布式序列策略配置
spring.shardingsphere.rules.sharding.tables.t_order.key-generate-strategy.column=id
#算法名称
spring.shardingsphere.rules.sharding.tables.t_order.key-generate-strategy.key-generator-name=alg_snowflake
spring.shardingsphere.rules.sharding.key-generators.alg_snowflake.type=SNOWFLAKE
注:在配置数据节点时,我们为了显示的更加简便易读可以使用行表达式,行表达式标识符可以使用 ${…},或 $->{…},前者与 Spring 本身的属性文件占位符冲突,因此在 Spring 环境中使用行表达式标识符建议使用 $->{…}
创建Order实体类:
@TableName("t_order")
@Data
public class Order {
// @TableId(type = IdType.ASSIGN_ID)
@TableId(type = IdType.AUTO) //配置了shardingSphere的雪花算法分布式序列
private Long id;
private String orderNo;
private Long userId;
private BigDecimal amount;
}
package com.yy.shardingsph.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yy.shardingsph.entity.Order;
import com.yy.shardingsph.mapper.OrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.List;
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
OrderMapper orderMapper;
@RequestMapping("insert")
public void testInsertOrder(){
for (long i=100;i<109;i++){
Order order = new Order();
order.setOrderNo("yygood"+i);
order.setUserId(1L);
order.setAmount(new BigDecimal(100));
orderMapper.insert(order);
}
}
@RequestMapping("select")
public void testSelectOrder(){
List<Order> list = orderMapper.selectList(null);
list.forEach(System.out::println);
}
@RequestMapping("selectByUserId")
public void testSelectOrderByUserId(){
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id",1L);
List<Order> list = orderMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
}
可以看到插入数据时的逻辑SQL和真实SQL。
查询数据时的逻辑SQL和真实SQL,我们可以发现真实SQL在查询时会分别对不同库里的order0表和order1表进行联合查询,最后将两次查询的结果合并起来显示。