一、序言
在理论业务中,单表数据增长较快,很容易达到数据瓶颈,比方单表百万级别数据量。当数据量持续增长时,数据的 查问性能
即便有索引的帮忙下也不尽如意,这时能够引入数据 分库分表
技术。
本文将基于 SpringBoot
+MybatisPlus
+Sharding-JDBC
+Mysql
实现企业级分库分表。
1、组件及版本抉择
SpringBoot 2.6.x | MybatisPlus 3.5.0 | Sharding-JDBC 4.1.1 | Mysql 5.7.35 |
2、预期指标
- 应用上述组件实现分库分表,简化起见只探讨分表技术
- 实现分表后的逻辑表与物理表间的增删查改
- 引入逻辑删除和应用 MybatisPlus 内置分页技术
残缺我的项目源码拜访地址。
二、代码实现
为了简化分表复杂性,专一于分表整体实现,简化分表逻辑:依照 UserId
的奇偶属性别离进行分表。以订单表这一典型场景为例,一般来说无关订单表,通常具备如下共性行为:
- 创立订单记录
- 查问 XX 用户的订单列表
- 查问 XX 用户的订单列表(分页)
- 查问 XX 订单详情
- 批改订单状态
- 删除订单(逻辑删除)
接下来通过代码实现上述指标。
(一)素材筹备
1、实体类
@Data
@TableName("bu_order")
public class Order {
@TableId
private Long orderId;
private Integer orderType;
private Long userId;
private Double amount;
private Integer orderStatus;
@TableLogic
@JsonIgnore
private Boolean deleted;
}
2、Mapper 类
@Mapper
public interface OrderMapper extends BaseMapper<Order> {}
3、全局配置文件
spring:
config:
use-legacy-processing: true
shardingsphere:
datasource:
ds1:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1:3306/sharding-jdbc2?serverTimezone=UTC
username: root
password: 123456
names: ds1
props:
sql:
show: true
sharding:
tables:
bu_order:
actual-data-nodes: ds1.bu_order_$->{0..1}
key-generator:
column: order_id
type: SNOWFLAKE
table-strategy:
inline:
algorithm-expression: bu_order_${user_id%2}
sharding-column: user_id
(二)增删查改
1、保留数据
因为根据主键的奇偶属性对原表分表,分表后每张表的数据量是分表前的二分之一。依据须要也能够自定义分表数量(比方 10 张),新分表后的数据量是不分表前的十分之一。
@Test
public void addOrders() {for (long i = 1; i <= 10; i++) {Order order = new Order();
order.setOrderId(i);
order.setOrderType(RandomUtil.randomEle(Arrays.asList(1, 2)));
order.setUserId(RandomUtil.randomEle(Arrays.asList(101L, 102L, 103L)));
order.setAmount(1000.0 * i);
orderMapper.insert(order);
}
}
2、查问列表数据
查问指定用户的订单列表。
@GetMapping("/list")
public AjaxResult list(Order order) {LambdaQueryWrapper<Order> wrapper = Wrappers.lambdaQuery(order);
return AjaxResult.success(orderMapper.selectList(wrapper));
}
3、分页查问数据
分页查问指定用户的订单列表
@GetMapping("/page")
public AjaxResult page(Page<Order> page, Order order) {return AjaxResult.success(orderMapper.selectPage(page, Wrappers.lambdaQuery(order)));
}
4、查问详情
通过订单 ID 查问订单详情。
@GetMapping("/detail/{orderId}")
public AjaxResult detail(@PathVariable Long orderId) {return AjaxResult.success(orderMapper.selectById(orderId));
}
5、删除数据
通过订单 ID 删除订单(逻辑删除)
@DeleteMapping("/delete/{orderId}")
public AjaxResult delete(@PathVariable Long orderId) {return AjaxResult.success(orderMapper.deleteById(orderId));
}
6、批改数据
批改数据个别波及局部列,比方批改订单表的订单状态等。
@PutMapping("/edit")
public AjaxResult edit(@RequestBody Order order) {return AjaxResult.success(orderMapper.updateById(order));
}
三、实践剖析
1、抉择分片列
抉择分片列是通过精心比照后确定的,对于订单类场景,须要频繁以用户 ID 为查问条件筛选数据,因而将同一个用户的订单数据寄存在一起有利于进步查问效率。
2、扩容
当分表后的表数据快速增长,能够预感行将达到瓶颈时,须要对分表进行扩容,扩容以 2 倍
的速率进行,扩容期间须要迁徙数据,工作量绝对可控。
喜爱本文点个♥️赞♥️反对一下,关注我下期再见,相干源码在 GitHub,视频解说在 B 站,本文珍藏在专题博客。