当前位置:首页 >娱乐 >SpringBoot3分库分表 一个数据库由多个数据表构成

SpringBoot3分库分表 一个数据库由多个数据表构成

2024-07-01 09:26:39 [百科] 来源:避面尹邢网

SpringBoot3分库分表

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

一、分库分表简介

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

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

SpringBoot3分库分表 一个数据库由多个数据表构成

SpringBoot3分库分表 一个数据库由多个数据表构成

垂直分片

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

SpringBoot3分库分表 一个数据库由多个数据表构成

水平分片

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

下面从案例实践中,看看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索引结构,如果没有搜索的需求,可以在订单表分页查询后去拼接其他结构;

@RestControllerpublic 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 =


责任编辑:武晓燕 来源: 知了一笑 分库分表数据数据库

(责任编辑:知识)

    推荐文章
    热点阅读