一、序言

在理论业务中,单表数据增长较快,很容易达到数据瓶颈,比方单表百万级别数据量。当数据量持续增长时,数据的查问性能即便有索引的帮忙下也不尽如意,这时能够引入数据分库分表技术。

本文将基于SpringBoot+MybatisPlus+Sharding-JDBC+Mysql实现企业级分库分表。

1、组件及版本抉择
SpringBoot 2.6.xMybatisPlus 3.5.0Sharding-JDBC 4.1.1Mysql 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类
@Mapperpublic 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张),新分表后的数据量是不分表前的十分之一。

@Testpublic 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站,本文珍藏在专题博客。