一、序言
在實際業務中,單表資料增長較快,很容易達到資料瓶頸,比如單表百萬級別資料量,當資料量繼續增長時,資料的查詢性能即使有索引的幫助下也不盡如意,這時可以引入資料分庫分表技術,
本文將基于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同樣精彩,收到您的star我會很激動,本文歸檔在專題博客,視頻講解在B站,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/435328.html
標籤:Java




