SpringBoot3分库分表
标签:ShardingSphere5.分库.分表;
一、简介
分库分表的设计和实现方式,在之前的内容中总结过很多,本文基于SpringBoot3和ShardingSphere5框架实现数据分库分表的能力;
不得不提ShardingSphere5文档中描述的两个基本概念:

垂直分片
按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用。在拆分之前,一个数据库由多个数据表构成,每个表对应着不同的业务。而拆分之后,则是按照业务将表进行归类,分布到不同的数据库中,从而将压力分散至不同的数据库。
水平分片
水平分片又称为横向拆分。 相对于垂直分片,它不再将数据根据业务逻辑分类,而是通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个分片仅包含数据的一部分。
下面从案例实践中,看看ShardingSphere5框架是如何实现分库分表的原理;
二、工程搭建
1、工程结构

2、依赖管理
这里只看两个核心组件的依赖:shardingsphere-jdbc组件是5.2.1版本,mybatis组件是3.5.13版本,在依赖管理中还涉及MySQL和分页等,并且需要添加很多排除配置,具体见源码;
<!-- Mybatis组件 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- ShardingSphere分库分表 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
三、配置详解
1、配置文件
此处只展示分库分表的相关配值,默认数据源使用db_master库,注意tb_order库表路由的策略和分片算法的关联关系,其他工程配置详见源码仓库;
spring:
# 分库分表配置
shardingsphere:
datasource:
# 默认数据源
sharding:
default-data-source-name: db_master
names: db_master,db_0,db_1
db_master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/shard_db
username: root
password: 123456
db_0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/shard_db_0
username: root
password: 123456
db_1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/shard_db_1
username: root
password: 123456
rules:
sharding:
tables:
# tb_order逻辑
tb_order:
actual-data-nodes: db_${0..1}.tb_order_${0..2}
# tb_order库路由
database-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: database_inline
# tb_order表路由
table-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: table_inline
sharding-algorithms:
# tb_order库路由算法
database_inline:
type: INLINE
props:
algorithm-expression: db_${order_id % 2}
# tb_order表路由算法
table_inline:
type: INLINE
props:
algorithm-expression: tb_order_${order_id % 3}
props:
sql-show: true
sql-comment-parse-enabled: true
2、配置原理
在配置中需要管理三个数据源,shard_db默认库,在操作不涉及需要路由的表时默认使用该数据源,shard_db_0和shard_db_1是tb_order逻辑表的路由库;

逻辑表tb_order整体使用两个数据库,每个库建3张结构相同相同的表,在操作tb_order数据时,会根据order_id字段值定位数据所属的分片节点;
- 库路由
db_${0..1}采用db_${order_id%2}的算法; - 表路由
tb_order_${0..2}采用tb_order_${order_id%3}的算法;
四、测试案例
1、主库操作
基于Mybatis持久层框架,实现对shard_db默认库的数据操作,注意控制台的日志打印,可以看到一系列解析逻辑以及库表节点的定位,分页查询使用PageHelper组件即可;
public class MasterTest {
@Autowired
private BuyerMapper buyerMapper ;
@Autowired
private SellerMapper sellerMapper ;
@Test
public void testBuyerQuery (){
// 主键查询
Buyer buyer = buyerMapper.selectByPrimaryKey(1) ;
System.out.println(buyer.getId()+";"+buyer.getBuyerName());
}
@Test
public void testBuyerInsert (){
// 新增数据
Buyer buyer = new Buyer() ;
buyer.setBuyerName("买家Three");
System.out.println(buyerMapper.insert(buyer));
}
@Test
public void testBuyerUpdate (){
// 更新数据
Buyer buyer = buyerMapper.selectByPrimaryKey(3) ;
if (buyer != null){
buyer.setBuyerName("Three买家");
System.out.println(buyerMapper.updateByPrimaryKey(buyer));
}
}
@Test
public void testSellerPage (){
// 1、设置分页和查询条件
PageHelper.startPage(2,2) ;
SellerExample sellerExample = new SellerExample() ;
sellerExample.setOrderByClause("id asc");
// 2、查询数据
List<Seller> sellerList = sellerMapper.selectByExample(sellerExample) ;
// 3、构建分页实体对象
PageInfo<Seller> pageInfo = new PageInfo<>(sellerList) ;
System.out.println(pageInfo);
}
}
2、分库操作
在对tb_order表执行增删改查时,会根据order_id的字段值计算库表的路由节点,注意分页时会查询所有的分库和分表,然后汇总查询的结果;
public class ShardTest {
@Autowired
private OrderMapper orderMapper ;
/**
* 写入100条数据
*/
@Test
public void testOrderInsert (){
for (int i=1 ; i<= 100 ; i++){
Order order = new Order(i,i%3+1,i%3+1) ;
// orderMapper.insert(order) ;
}
}
@Test
public void testOrderQuery (){
Order order = orderMapper.selectByPrimaryKey(5) ;
System.out.println(order);
}
@Test
public void testOrderUpdate (){
Order order = orderMapper.selectByPrimaryKey(100) ;
if (order != null){
// 原数据:买家和卖家ID都是2
order.setBuyerId(1);
order.setSellerId(3);
orderMapper.updateByPrimaryKey(order) ;
}
}
@Test
public void testOrderPage (){
// 1、设置分页和查询条件
PageHelper.startPage(1,10) ;
OrderExample orderExample = new OrderExample() ;
orderExample.createCriteria().andBuyerIdEqualTo(2).andSellerIdEqualTo(2);
orderExample.setOrderByClause("order_id desc");
// 2、查询数据
List<Order> orderList = orderMapper.selectByExample(orderExample) ;
// 3、构建分页实体对象
PageInfo<Order> pageInfo = new PageInfo<>(orderList) ;
System.out.println(pageInfo);
}
}
3、综合查询
编写一个订单详情查询接口,同时使用三个库构建数据结构;如果是基于列表数据的检索,比较常规做法的是构建ES索引结构,如果没有搜索的需求,可以在订单表分页查询后去拼接其他结构;
@RestController
public class OrderController {
@Resource
private BuyerMapper buyerMapper ;
@Resource
private SellerMapper sellerMapper ;
@Resource
private OrderMapper orderMapper ;
/**
* 查询订单详情
*/
@GetMapping("/order/info/{orderId}")
public Map<String,Object> orderInfo (@PathVariable Integer orderId){
Map<String,Object> orderMap = new HashMap<>() ;
Order order = orderMapper.selectByPrimaryKey(orderId) ;
if (order != null){
orderMap.put("order",order) ;
orderMap.put("buyer",buyerMapper.selectByPrimaryKey(order.getBuyerId())) ;
orderMap.put("seller",sellerMapper.selectByPrimaryKey(order.getSellerId())) ;
}
return orderMap ;
}
}
查看SQL语句
db_master ::: select id, buyer_name from tb_buyer where id = ? ::: [1]
db_master ::: select id, seller_name from tb_seller where id = ? ::: [3]
db_0 ::: select order_id, seller_id, buyer_id from tb_order_1 where order_id = ? ::: [100]
五、参考源码
文档仓库:
https://gitee.com/cicadasmile/butte-java-note
源码仓库:
https://gitee.com/cicadasmile/butte-spring-parent
SpringBoot3分库分表的更多相关文章
- CRL快速开发框架系列教程十一(大数据分库分表解决方案)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- 重磅来袭,使用CRL实现大数据分库分表方案
关于分库分表方案详细介绍 http://blog.csdn.net/bluishglc/article/details/7696085 这里就不作详细描述了 分库分表方案基本脱离不了这个结构,受制于实 ...
- 利用sharding-jdbc分库分表
sharding-jdbc是当当开源的一款分库分表的数据访问层框架,能对mysql很方便的分库.分表,基本不用修改原有代码,只要配置一下即可,完整的配置参考以下内容: <?xml version ...
- MySQL分库分表总结
单库单表 单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到. 单库多表 随着用户数量的增加,user表的数据量会越来越大,当数 ...
- 数据库分库分表(sharding)系列(一) 拆分规则
第一部分:实施策略 数据库分库分表(sharding)实施策略图解 1. 垂直切分垂直切分的依据原则是:将业务紧密,表间关联密切的表划分在一起,例如同一模块的表.结合已经准备好的数据库ER图或领域模型 ...
- MYSQL性能优化分享(分库分表)
1.分库分表 很明显,一个主表(也就是很重要的表,例如用户表)无限制的增长势必严重影响性能,分库与分表是一个很不错的解决途径,也就是性能优化途径,现在的案例是我们有一个1000多万条记录的用户表mem ...
- Mysql分库分表方案
Mysql分库分表方案 1.为什么要分表: 当一张表的数据达到几千万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间. m ...
- Mysql分表和分区的区别、分库分表介绍与区别
分表和分区的区别: 一,什么是mysql分表,分区 什么是分表,从表面意思上看呢,就是把一张表分成N多个小表,具体请看:mysql分表的3种方法 什么是分区,分区呢就是把一张表的数据分成N多个区块,这 ...
- MYSQL分库分表和不停机更改表结构
在MYSQL分库分表中我们一般是基于数据量比较大的时间对mysql数据库一种优化的做法,下面我简单的介绍一下mysql分表与分库的简单做法. .分库分表 很明显,一个主表(也就是很重要的表,例如用户表 ...
- MySQL分库分表总结参考
单库单表 单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到. 单库多表 随着用户数量的增加,user表的数据量会越来越大,当数 ...
随机推荐
- 雪球 app 实战(1)
开头 因为理论篇结束之后,需要一个实战,估选用了雪球app作为一个作业 业务场景: 雪球 app 自选设置(入口位于 行情 模块) 作业内容 使用 百度脑图 编写 思维导图 [自选设置]模块的测试用例 ...
- 2022-11-04:给定一个正数n,表示有多少个节点 给定一个二维数组edges,表示所有无向边 edges[i] = {a, b} 表示a到b有一条无向边 edges一定表示的是一个无环无向图,也
2022-11-04:给定一个正数n,表示有多少个节点 给定一个二维数组edges,表示所有无向边 edges[i] = {a, b} 表示a到b有一条无向边 edges一定表示的是一个无环无向图,也 ...
- 2021-10-08:填充每个节点的下一个右侧节点指针。给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找
2021-10-08:填充每个节点的下一个右侧节点指针.给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点.填充它的每个 next 指针,让这个指针指向其下一个右侧节点.如果找 ...
- Selenium - 浏览器操作
Selenium - 浏览器操作 获取浏览器信息 from selenium import webdriver driver = webdriver.Chrome() driver.get(" ...
- python 之路,Django rest framework 初探
摘自 金角大王 https://www.cnblogs.com/alex3714/articles/7131523.html Django rest framework介绍 Django REST ...
- 【Java】JTable的数据刷新
前言 这段时间在写一个大实验,水果超市管理系统,yes,我觉得挺大的,但是就当成了一个实验,接下来还有一个课程设计和一个实训,more bigger... 问题 在我把其他的都写好的时候去写UI层,发 ...
- 2019年蓝桥杯C/C++大学B组省赛真题(特别数的和)
题目描述: 小明对数位中含有2.0.1.9 的数字很感兴趣(不包括前导0) 在1到40中这样的数包括1.2.9.10 至32.39 和40,共28 个,他们的和是574. 请问,在1到n 中,所有这样 ...
- 【QCustomPlot】性能提升之修改源码(版本 V2.x.x)
说明 使用 QCustomPlot 绘图库的过程中,有时候觉得原生的功能不太够用,比如它没有曲线平滑功能:有时候又觉得更新绘图数据时逐个赋值效率太低,如果能直接操作内存就好了:还有时候希望减轻 CPU ...
- 7-9 《Fibonacci 数列》
7-9 <Fibonacci 数列> 思路:吃过前面<序列求和>问题的亏 但还是要尝试一下循环大法 Fn=Fn-1+Fn-2 定义int型 aFn-1 , bFn-2 , cF ...
- 一篇文章带你详细了解axios的封装
axios 封装 对请求的封装在实际项目中是十分必要的,它可以让我们统一处理 http 请求.比如做一些拦截,处理一些错误等.本篇文章将详细介绍如何封装 axios 请求,具体实现的功能如下 基本配置 ...