SpringBoot3分库分表

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用;水平分片又称为横向拆分,是通过某些字段根据某种规则将数据分散至多个库或表中。

标签:ShardingSphere5.分库.分表;

一、简介

分库分表的设计和实现方式,在之前的内容中总结过很多,本文基于SpringBoot3ShardingSphere5框架实现数据分库分表的能力;

不得不提ShardingSphere5文档中描述的两个基本概念:

1.png

垂直分片

按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用。在拆分之前,一个数据库由多个数据表构成,每个表对应着不同的业务。而拆分之后,则是按照业务将表进行归类,分布到不同的数据库中,从而将压力分散至不同的数据库。

水平分片

水平分片又称为横向拆分。 相对于垂直分片,它不再将数据根据业务逻辑分类,而是通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个分片仅包含数据的一部分。

下面从案例实践中,看看ShardingSphere5框架是如何实现分库分表的原理;

二、工程搭建

1、工程结构

2.png

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_{
   
   mathJaxContainer[0]}{
   
   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_0shard_db_1tb_order逻辑表的路由库;

3.png

逻辑表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
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
5月前
|
Java
SpringBoot整合sharding-jdbc实现分库分表
SpringBoot整合sharding-jdbc实现分库分表
167 1
|
11月前
|
SQL Java 中间件
Springboot集成 Sharding-JDBC + Mybatis-Plus实现分库分表(源码)
Sharding-jdbc是开源的数据库操作中间件;定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
|
SQL cobar 算法
SpringBoot 2 种方式快速实现分库分表,轻松拿捏!
SpringBoot 2 种方式快速实现分库分表,轻松拿捏!
4985 6
SpringBoot 2 种方式快速实现分库分表,轻松拿捏!
|
druid Java
springboot shardingsphere druid 动态数据源切换及分库分表
springboot shardingsphere druid 动态数据源切换及分库分表
|
Java 关系型数据库 MySQL
java springboot mysql shardingsphere 分库分表 下 (分库分表)
java springboot mysql shardingsphere 分库分表 下 (分库分表)
|
Java 关系型数据库 MySQL
java springboot mysql shardingsphere 分库分表 上 (单库分表)
java springboot mysql shardingsphere 分库分表 上 (单库分表)
|
算法 测试技术 Apache
Springboot2.x + ShardingSphere 实现分库分表
Springboot2.x + ShardingSphere 实现分库分表
123 0
|
SQL 算法 Cloud Native
【ShardingSphere技术专题】「ShardingJDBC」SpringBoot之整合ShardingJDBC实现分库分表(JavaConfig方式)
【ShardingSphere技术专题】「ShardingJDBC」SpringBoot之整合ShardingJDBC实现分库分表(JavaConfig方式)
243 0
【ShardingSphere技术专题】「ShardingJDBC」SpringBoot之整合ShardingJDBC实现分库分表(JavaConfig方式)
|
算法 Java 关系型数据库
springboot 2.0集成mycat 1.6 实现分库分表
springboot 2.0集成mycat 1.6 实现分库分表
645 0
springboot 2.0集成mycat 1.6 实现分库分表
|
监控 druid 算法
SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 实现分库分表
 今天项目不忙,想搞一下shardingJDBC分库分表看看,主要想实现以下几点: 舍弃xml配置,使用.yml或者.properties文件+java的方式配置spring。 使用 Druid 作为数据库连接池,同时开启监控界面,并支持监控多数据源。 不依赖 com.dangdang 的 sharding-jdbc-core 包。此包过于古老,最后一次更新在2016年。目测只是封装了一层,意义不大。感觉如果不是dangdang公司内部开发,没必要用这个包。(且本人实测不能和最新的Druid包一起用,insert语句报错)
SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 实现分库分表