文章目录
当单表记录达到500万条或磁盘空间占用达2GB时需要考虑水平分表。水平分表是按行切分为多个表,若放在同一个服务器里能够满足性能要求就不用分库。若不能满足要求就要分库了,将表放在不同的服务器上。
一、准备服务器
根据user_id选择是哪台服务器的数据库,在根据order_id选择到具体的哪张表。
1.1 创建server-order0和server-order1容器
server-order0
docker run -p 3310:3306 --name server-order0 \
-v /mydata/mysql-master/log:/var/log/mysql \
-v /mydata/mysql-master/data:/var/lib/mysql \
-v /mydata/mysql-master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
server-order1
docker run -p 3311:3306 --name server-order1 \
-v /mydata/mysql-master/log:/var/log/mysql \
-v /mydata/mysql-master/data:/var/lib/mysql \
-v /mydata/mysql-master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
1.2 创建数据库
注意,水平分片的id需要在业务层实现,不能依赖数据库的主键。
CREATE DATABASE db_order;
CREATE TABLE t_order0(
`id` bigint NOT NULL,
`order_no` VARCHAR(30) NOT NULL,
`user_id` bigint NULL DEFAULT NULL,
`amount` decimal(10, 2) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE t_order1(
`id` bigint NOT NULL,
`order_no` VARCHAR(30) NOT NULL,
`user_id` bigint NULL DEFAULT NULL,
`amount` decimal(10, 2) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
);
1.3创建实体类
@TableName("t_order") //逻辑表名
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
@TableId(type = IdType.ASSIGN_ID) //分布式id
private Long id;
private String orderNO;
private Long userId;
private BigDecimal amount;
}
1.4 创建mapper
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
二、基本水平分片配置
2.1 基本配置
#====================基本配置
# 应用名称
spring.application.name=sharding-jdbc-demo
#开发环境设置
spring.profiles.active=dev
# 运行模式
spring.shardingsphere.mode.type=Memory
#打印SQL
spring.shardingsphere.props.sql-show=true
2.2 数据源配置
# 配置真实数据源
spring.shardingsphere.datasource.names=server-order0,server-order1
# 配置第 1 个数据源
spring.shardingsphere.datasource.server-order0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.server-order0.jdbc-url=jdbc:mysql://mysql3:3310/db_order
spring.shardingsphere.datasource.server-order0.username=root
spring.shardingsphere.datasource.server-order0.password=root
# 配置第 2个数据源
spring.shardingsphere.datasource.server-order1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.server-order1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.server-order1.jdbc-url=jdbc:mysql://mysql5:33011/db_order
spring.shardingsphere.datasource.server-order1.username=root
spring.shardingsphere.datasource.server-order1.password=root
2.3 标准分片表配置
# =================标准分片表配置(数据节点配置)
#spring.shardingsphere.rules.sharding.tables.<table-name>.actual-data-nodes=值
# 由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。
# 缺省表示使用已知数据源与逻辑表名称生成数据节点,用于广播表(即每个库中都需要一个同样的表用于关联查询,多为字典表)或只分库不分表且所有库的表结构完全一致的情况
#<table-name>:逻辑表名
#spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=server-order0.t_order_0,server-order0.t_order_1,server-order1.t_order_0,server-order1.t_order_1
spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=server-order$->{0..1}.t_order$->{0..1}
2.4 分片算法配置
水平分库
#=================水平分库
# 分库策略,缺省表示使用默认分库策略,以下的分片策略只能选其一
# 用于单分片键的标准分片场景
# 分片列名称
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=my_inline_user_id
# =================分片算法配置
# 分片算法类型
spring.shardingsphere.rules.sharding.sharding-algorithms.my_inline_user_id.type=INLINE
# 分片算法属性配置
spring.shardingsphere.rules.sharding.sharding-algorithms.my_inline_user_id.props.algorithm-expression=server-order$->{user_id % 2}
水平分表
# 分表策略
# 分片列名称
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.sharding-algorithms.alg_hash_mod.type=HASH_MOD
# 分片算法属性配置
spring.shardingsphere.rules.sharding.sharding-algorithms.alg_hash_mod.props.sharding-count=2
2.5 测试
@SpringBootTest
public class ShardTest {
@Autowired
private OrderMapper orderMapper;
/**
* 水平分片:分表插入数据测试
*/
@Test
public void testInsertOrderTableStrategy(){
for (long i = 1; i <5 ; i++) {
Order order=new Order();
order.setOrderNo("ATGUIGU"+i);//分表键
order.setUserId(1l);//分库键
order.setAmount(new BigDecimal(100));
orderMapper.insert(order);
}
for (long i = 5; i <9 ; i++) {
Order order=new Order();
order.setOrderNo("ATGUIGU"+i);//分表键
order.setUserId(2l);//分库键
order.setAmount(new BigDecimal(100));
orderMapper.insert(order);
}
}
/**
* 水平分片:查询所有记录
*/
@Test
public void testShardSelectAll(){
List<Order> orderList = orderMapper.selectList(null);
orderList.forEach(System.out::println);
}
/**
* 水平分片:根据user_id查询记录
*/
@Test
public void testShardSelectByUserId(){
QueryWrapper<Order> orderQueryWrapper=new QueryWrapper<>();
orderQueryWrapper.eq("user_id",1L);
List<Order> orderList = orderMapper.selectList(orderQueryWrapper);
orderList.forEach(System.out::println);
}
三、分布式主键
水平分片需要关注全局序列,因为不能简单的使用基于数据库的主键自增。
这里有两种方案,一种是基于MyBatisPlus的id策略,一种是ShardingSphere-jdbc的全局序列配置。
- 基于MyBatisPlus的id策略:将Order类的id设置成如下形式
@TableId(type = IdType.ASSIGN_ID) //分布式id
private Long id;
- 基于ShardingSphere-jdbc的全局序列配置:和前面的MyBatisPlus的策略二选一
//当配置了ShardingSphere-jdbc的分布式序列时,自动使用ShardingSphere-jdbc的分布式序列
//当没有配置了ShardingSphere-jdbc的分布式序列时,自动依赖数据库的自增策略
@TableId(type = IdType.AUTO)
//@TableId(type = IdType.ASSIGN_ID) //分布式id(默认值)
private Long id;
# 分布式序列策略配置
# 分布式序列列名称
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.shardingsphere.rules.sharding.key-generators.alg_snowflake.props.xxx=