mybatis plus + shardingsphere读写分离+分表

需求场景

在实际业务中,高并发的数据库中,单个数据库性能受限,尤其是在有读写夹杂在一起的时候。我们都知道,系统中大部分都是读操作,写操作是占用比较小的部分的,所有就有了读写分离的操作,读可以专门读的数据库,而写操作(CUD)就专门在主数据库中进行。
读写分流
而分表则是为了避免单个的表的数据量太大,根据ali开发规范来说,一个表的上限是2G,数据量上限为500w,但是通常来说虽然我们不一定完全遵循,但是2000w条数据,对于系统来说也是比较大了,而2000w数据来说是非常正常的,一些比如日志表啥的,动不动是10G+以上的数据,所以分表也是非常必要的。

方案

仅仅是主从分离的话,可以使用mybatis plus系列的dynamic-datasource,参考data-source来实现主从分离,非常方便,但是暂时没有分表功能。所以我们使用mybaits plus + shardingsphere方案

方案特点
dynamic-datasource简单方便,支持开发指定从库的数据查询 ,不支持分表
shardingshpere功能强大,比较复杂,支持分表,暂时不支持指定库操作
什么是mybatis plus

mybatis plus是国内基于mybatis做出一个开源工具包,

是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

简单来说就是代替mybatis的一个orm访问工具,但是功能更强大,这里不多赘述,因为我们就是用它的orm功能,其他的查看文档。
官方文档

什么是shardingsphere

官方文档

Apache ShardingSphere 是一款分布式的数据库生态系统, 可以将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。

Apache ShardingSphere 设计哲学为 Database Plus,旨在构建异构数据库上层的标准和生态。 它关注如何充分合理地利用数据库的计算和存储能力,而并非实现一个全新的数据库。 它站在数据库的上层视角,关注它们之间的协作多于数据库自身。

shardingSphere的功能非常强大,但是我们暂时只需要使用到sharding-jdbc,sharding-jdbc时什么呢?

ShardingSphere-JDBC 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务

我的理解就是jdbc api的重写和封装。

系统结构
  1. spring boot
  2. mybatis plus
  3. shardingsphere
    maven依赖如下:
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <!-- <version>8.0.21</version> 版本Spring-Boot-Parent中已带 -->
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/sharding-jdbc-spring-boot-starter -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-core-common</artifactId>
            <version>4.1.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>
数据结构

在开始之前我们,我们需要创建sql,数据结构如下:
order (1) —order_id----> order_item(n),请将idx换成0~1

sql
CREATE TABLE `t_order_idx` (
  `order_id` bigint NOT NULL,
  `order_no` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `create_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

CREATE TABLE `t_order_item_0` (
  `item_id` bigint NOT NULL,
  `order_no` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `item_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  `order_id` bigint DEFAULT NULL,
  PRIMARY KEY (`item_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
如何配置

如果上述步骤完成后,那么需要做的仅仅做些配置了,yaml注册文件如下:

spring:
  shardingsphere:
#    数据库名称
    datasource:
      names: master,slave-0,slave-1
      master:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/asx?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: root
      slave-0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3307/asx?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: root
      slave-1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3308/asx?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: root
#  配置分片规则
    sharding:
      tables:
        t_order:
          key-generator:
            column: order_id
            type: SNOWFLAKE
          actual-data-nodes: ms.t_order_$->{0..1}
          database-strategy:
            inline:
              sharding-column: order_id
              algorithm-expression: ms
          table-strategy:
            inline:
              sharding-column: order_id
              algorithm-expression: t_order_$->{order_id % 2}
        t_order_item:
          key-generator:
            column: item_id
            type: SNOWFLAKE
          actual-data-nodes: ms.t_order_item_$->{0..1}
          database-strategy:
            inline:
              sharding-column: order_id
              algorithm-expression: ms
          table-strategy:
            inline:
              sharding-column: order_id
              algorithm-expression: t_order_item_$->{order_id % 2}
      binding-tables: t_order,t_order_item
      broadcast-tables: t_config
#      default-data-source-name: master
      defaultTableStrategy:
        none:
#      配置主从规则
      masterSlaveRules:
        ms:
          masterDataSourceName: master
          slaveDataSourceNames:
            - slave-0
            - slave-1
          loadBalanceAlgorithmType: ROUND_ROBIN
    props:
      sql:
        show: true                                          # 打印SQL

结果校验
校验数据插入问题

编写insert case

 @Test
    public void testCreateOrder() {
        int start = 0;
        for (int i = start; i < start + 10; i++) {
            BtOrderModel order = new BtOrderModel();
            order.setOrderNo("A000" + i);
            order.setCreateName("订单 " + i);
            order.setPrice(new BigDecimal("" + i));
            btOrderMapper.insert(order);

            BtOrderItemModel orderItem = new BtOrderItemModel();
            orderItem.setOrderId(order.getOrderId());
            orderItem.setOrderNo("A000" + i);
            orderItem.setItemName("服务项目" + i);
            orderItem.setPrice(new BigDecimal("" + i));
            btOrderItemMapper.insert(orderItem);
        }
    }

查看日志

INFOLogic SQL: INSERT INTO t_order  ( order_id,
order_no,
create_name,
price )  VALUES  ( ?,
?,
?,
? )
INFOSQLStatement: InsertStatementContext(super=CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.InsertStatement@3a5e2525, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@6546371), tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@6546371, columnNames=[order_id, order_no, create_name, price], insertValueContexts=[InsertValueContext(parametersCount=4, valueExpressions=[ParameterMarkerExpressionSegment(startIndex=75, stopIndex=75, parameterMarkerIndex=0), ParameterMarkerExpressionSegment(startIndex=78, stopIndex=78, parameterMarkerIndex=1), ParameterMarkerExpressionSegment(startIndex=81, stopIndex=81, parameterMarkerIndex=2), ParameterMarkerExpressionSegment(startIndex=84, stopIndex=84, parameterMarkerIndex=3)], parameters=[1584134049671151617, A00011, 订单 11, 11])], generatedKeyContext=Optional[GeneratedKeyContext(columnName=order_id, generated=false, generatedValues=[1584134049671151617])])
INFOActual SQL: master ::: INSERT INTO t_order_1  ( order_id,
order_no,
create_name,
price )  VALUES  (?, ?, ?, ?) ::: [1584134049671151617, A00011, 订单 11, 11]

actual sql中采用的是master数据库

校验数据查询问题

编写一个url为:

GET http://localhost:9380/master/slave/sharding/order/{id} 

的接口,让后手动修改数据库中的值,调用两次,就会发现结果不同,当然你也可以查看日志
在这里插入图片描述

遇到的问题

问题1: 插入insert的时候,主键不回写,如上面的orderId,orderId是根据雪花算法生成

解决方案: Model中增加主键注释

  @TableId(type = IdType.ASSIGN_ID)
  1. 分页查询
    分页查询如果没有shardingKey的话,会遍历每个表,然后做集合分页,这样的话效率比较低
参考文档
  1. Mysql支持分库请参考:windows配置mysql8.0主从数据库,主从数据同步。
    分库的话配置参考:
  2. shardingsphere配置手册
  3. ShardingSphere分库分表3-内核原理及核心源码解析
源码参考

spring-data-sharding

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ShardingSphere:SpringBoot2+MybatisPlus+读写分离+分库分表课程目标快速的掌握读写分离+分表的实战,即插即用适用人群IT从业人员,开发人员,Java从业者,互联网从业者,性能调优人群课程简介ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈。它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成,shardingSphere定位为关系型数据库中间件。 Sharding-JDBCSharding-JDBC是Sharding-Sphere的第一个产品,也是Sharding-Sphere的前身,是当当网开源的一个产品。定位为轻量级的Java框架,在Java的JDBC层提供额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。他们均提供标准化的数据分片、读写分离、柔性事务和数据治理功能,可适用于如Java同构、异构语言、容器、云原生等各种多样化的应用场景。Sharding-JDBC可以通过Java,YAML,Spring命名空间和Spring Boot Starter四种方式配置,开发者可根据场景选择适合的配置方式。课程特色 本章节以尽量短的时间,为使用者提供最简单的ShardingSphere的快速入门。课程说明该课程属于系列课程,分为读写分离,分库不分表,不分库分表,分库分表读写分离+分库分表共5个回合。本课程属于其中一个回合,请各位小哥哥们注意,课程的标题哦~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值