参考资料

github.com/GoodBoy2333/sharding-jdbc-demo【GitHub的简单demo】
shardingsphere.apache.org/document/current/cn/overview/【shardingsphere文档】

内容总结

1.SharddingSphere基础知识

① 分库分表的目的,插件选择和问题及其解决方案

② ShardShpere的介绍,三个子项目、表类型,关于其数据节点和分片机制相关概念

2.ShardSphere实战

基于前面提供的GitHub demo参考链接,对其进行改进

① 使用MyBatis-Plus,简化定义PO和SQL语句调用

② 将数据库表的分片逻辑进行修改,每个库都有四个orders和orders_item的分表

③ 编写测试

3.关键版本信息

① JDK1.8

② SpringBoot 2.7.1

③ ShardingSphere4.0.1

4.考虑的改进方案

① userId是Integer类型,如果是字符串类型,可以修改为取其hashcode

② 如果只有mall_1和mall_2进行分库分表,那么mall_0作为主库不进行分库分表的处理: 添加默认策略,

分库的时候需要在对应的表达式上加1

ShardingSphere基础知识

个人博客-分库分表理论【这是之前写的分库分表理论】

1. 分库分表目的

分库分表的主要原因是为了解决数据库性能瓶颈和扩展性问题,具体包括以下几点:

  • 性能提升:单表数据量过大(例如千万级以上)时,查询、插入等操作性能会显著下降,分表后可以减少单表数据量,提升性能。
  • 容量扩展:单库的存储容量有限,分库可以将数据分散到多个数据库实例,突破单机存储限制。
  • 高并发支持:随着用户量和访问量的增加,单库的并发处理能力会成为瓶颈,分库分表可以将请求分散到多个节点,降低单点压力。
  • 维护性:分库分表后,数据分布更清晰,便于管理和维护,比如归档历史数据或按业务拆分。

2. 分库分表的插件选择

Sharding-Jdbc 和 Mycat

  • 为什么选择 Sharding-Jdbc?

是client层的方案,优点是不需要部署、运维成本低,不需要代理层的二次转发请求,性能很高

  • 为什么不选择Mycat?

缺点是需要自己部署;

优点是对各个项目是透明的。

3. 分库分表带来的问题

  • 本地事务无效

解决:改用TCC和ShardingSphere柔性事务

  • 跨表join问题

解决:进行冗余实现(空间换时间)

  • 自增主键唯一性问题

解决:修改雪花算法生成或者UUID等

4. 什么是ShardingSphere?

分库分表的中间件,它是一个开源的分布式数据库中间件解决方案,支持分库分表、读写分离、分布式事务等功能,主要用于实现分库分表。

5. ShardingSphere的三个子项目

  • sharding-Jdbc

轻量级的Java框架,支持任意实现JDBC规范的数据库,比如MySQL

功能:是将SQL语句按照分片策略分散到多个数据库中执行,从而实现分库分表。

  • Sharding-Proxy

基于MySQL协议的代理服务,将单库应用转换为分库分表的应用。

  • Sharding-Sidecar

基于ServiceMesh的边车代理。

6. ShardingSphere表的分类

  • 逻辑表:针对水平拆分

水平拆分后表的统一逻辑名称。

根据逻辑表名shardingsphere自动路由到对应的真实表

示例:订单表按主键尾数分片为 t_order_0 到 t_order_9,逻辑表名为 t_order。

  • 真实表

数据库中实际存在的数据库表,比如t_order_0、t_order_1等

  • 绑定表

定义:分片规则一致的一组表,通常用于关联查询。

在配置中的体现:

用于优化查询,当orders 和 orders_item 的管理,确保两表的数据在同一个分片上,避免不必要的跨库或者跨表操作。

# 绑定表:分片规则一致的主表和子表
binding-tables[0]: orders, orders_item
  • 广播表

定义:所有数据源中都存在的表,结构和数据一致。

用途:适合数据量小且需与分片表关联查询的场景,如字典表。

特点:无需分片,所有节点同步更新。

  • 单表

定义:分片数据源中仅唯一存在的表。

用途:数据量小、无需分片的表,如配置表。

7. 什么是数据节点

  • 是什么

数据分片的最小单位,用于表示分布式数据库系统中数据的物理存储位置。

连接逻辑表和真实表的关键桥梁,

  • 组成

数据源名称和真实表名称组合而成,

​​在这里插入图片描述

  • 在配置中的体现
tables:
  orders:
    actualDataNodes: ds-mall-0.orders_$->{[0,2]}, ds-mall-1.orders_$->{[1,3]}

8. 关于分片机制

  • 相关的概念

分片策略:整体框架。【default-table-strategy】

分片键:指定 user_id。

分片算法:通过自定义算法实现精确和范围分片。

标准分片算法:使用 standard 类型处理单一键分片。

ShardingSphere实战

1. SQL语句

① 数据库1:mall_0

/*
MySQL Backup
Database: mall_0
Backup Time: 2020-07-31 15:16:06
*/
UNLOCK TABLES ;
DROP DATABASE IF EXISTS `mall_0`;
CREATE DATABASE IF NOT EXISTS `mall_0` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
USE mall_0;
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS   `order_config`;
DROP TABLE IF EXISTS   `orders_0`;
DROP TABLE IF EXISTS   `orders_1`;
DROP TABLE IF EXISTS   `orders_2`;
DROP TABLE IF EXISTS   `orders_3`;
DROP TABLE IF EXISTS   `orders_item_0`;
DROP TABLE IF EXISTS   `orders_item_1`;
DROP TABLE IF EXISTS   `orders_item_2`;
DROP TABLE IF EXISTS   `orders_item_3`;
CREATE TABLE `order_config` (
                                `id` int(11) NOT NULL   COMMENT '编号',
                                `pay_timeout` int(11) DEFAULT NULL COMMENT '支付超时时间;单位:分钟',
                                PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='订单配置表';
CREATE TABLE `orders_0` (
                            `id` bigint(11) NOT NULL   COMMENT '订单编号',
                            `user_id` int(16) DEFAULT NULL COMMENT '用户编号',
                            PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单表';
CREATE TABLE `orders_1` (
                            `id` bigint(11) NOT NULL   COMMENT '订单编号',
                            `user_id` int(16) DEFAULT NULL COMMENT '用户编号',
                            PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单表';
CREATE TABLE `orders_2` (
                            `id` bigint(11) NOT NULL   COMMENT '订单编号',
                            `user_id` int(16) DEFAULT NULL COMMENT '用户编号',
                            PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单表';
CREATE TABLE `orders_3` (
                            `id` bigint(11) NOT NULL   COMMENT '订单编号',
                            `user_id` int(16) DEFAULT NULL COMMENT '用户编号',
                            PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单表';
CREATE TABLE `orders_item_0` (
                                 `id` bigint(11) NOT NULL   COMMENT '订单编号',
                                 `order_id` bigint(11) DEFAULT NULL COMMENT '订单编号',
                                 `user_id` int(16) DEFAULT NULL,
                                 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单详情表';
CREATE TABLE `orders_item_1` (
                                 `id` bigint(11) NOT NULL   COMMENT '订单编号',
                                 `order_id` bigint(11) DEFAULT NULL COMMENT '订单编号',
                                 `user_id` int(16) DEFAULT NULL,
                                 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单详情表';
CREATE TABLE `orders_item_2` (
                                 `id` bigint(11) NOT NULL   COMMENT '订单编号',
                                 `order_id` bigint(11) DEFAULT NULL COMMENT '订单编号',
                                 `user_id` int(16) DEFAULT NULL,
                                 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB   DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单详情表';
CREATE TABLE `orders_item_3` (
                                 `id` bigint(11) NOT NULL   COMMENT '订单编号',
                                 `order_id` bigint(11) DEFAULT NULL COMMENT '订单编号',
                                 `user_id` int(16) DEFAULT NULL,
                                 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单详情表';
BEGIN;
LOCK TABLES   `order_config` WRITE;
DELETE FROM   `order_config`;
UNLOCK TABLES;
COMMIT;
BEGIN;
LOCK TABLES   `orders_0` WRITE;
DELETE FROM   `orders_0`;
UNLOCK TABLES;
COMMIT;
BEGIN;
LOCK TABLES   `orders_2` WRITE;
DELETE FROM   `orders_2`;
INSERT INTO   `orders_2` (`id`,`user_id`) VALUES (495962620172435456, 2);
UNLOCK TABLES;
COMMIT;
BEGIN;
LOCK TABLES   `orders_item_0` WRITE;
DELETE FROM   `orders_item_0`;
UNLOCK TABLES;
COMMIT;
BEGIN;
LOCK TABLES   `orders_item_2` WRITE;
DELETE FROM   `orders_item_2`;
INSERT INTO   `orders_item_2` (`id`,`order_id`,`user_id`) VALUES (495972280044617728, 495962620172435456, 2),(495972281172885505, 495962620172435456, 2),(495972283899183104, 495962620172435456, 2);
UNLOCK TABLES;
COMMIT;

② 数据库2:mall_1

/*
MySQL Backup
Database: mall_1
Backup Time: 2020-07-31 15:16:44
*/
UNLOCK TABLES ;
DROP DATABASE IF EXISTS `mall_1`;
CREATE DATABASE IF NOT EXISTS `mall_1` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
USE mall_1;
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS   `order_config`;
DROP TABLE IF EXISTS   `orders_0`;
DROP TABLE IF EXISTS   `orders_1`;
DROP TABLE IF EXISTS   `orders_2`;
DROP TABLE IF EXISTS   `orders_3`;
DROP TABLE IF EXISTS   `orders_item_0`;
DROP TABLE IF EXISTS   `orders_item_1`;

DROP TABLE IF EXISTS   `orders_item_2`;
DROP TABLE IF EXISTS   `orders_item_3`;
CREATE TABLE `order_config` (
                                `id` int(11) NOT NULL   COMMENT '编号',
                                `pay_timeout` int(11) DEFAULT NULL COMMENT '支付超时时间;单位:分钟',
                                PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='订单配置表';
CREATE TABLE `orders_0` (
                            `id` bigint(11) NOT NULL   COMMENT '订单编号',
                            `user_id` int(16) DEFAULT NULL COMMENT '用户编号',
                            PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单表';
CREATE TABLE `orders_1` (
                            `id` bigint(11) NOT NULL   COMMENT '订单编号',
                            `user_id` int(16) DEFAULT NULL COMMENT '用户编号',
                            PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单表';
CREATE TABLE `orders_2` (
                            `id` bigint(11) NOT NULL   COMMENT '订单编号',
                            `user_id` int(16) DEFAULT NULL COMMENT '用户编号',
                            PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单表';
CREATE TABLE `orders_3` (
                            `id` bigint(11) NOT NULL   COMMENT '订单编号',
                            `user_id` int(16) DEFAULT NULL COMMENT '用户编号',
                            PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单表';
CREATE TABLE `orders_item_0` (
                                 `id` bigint(11) NOT NULL   COMMENT '订单编号',
                                 `order_id` bigint(11) DEFAULT NULL COMMENT '订单编号',
                                 `user_id` int(16) DEFAULT NULL,
                                 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单详情表';
CREATE TABLE `orders_item_1` (
                                 `id` bigint(11) NOT NULL   COMMENT '订单编号',
                                 `order_id` bigint(11) DEFAULT NULL COMMENT '订单编号',
                                 `user_id` int(16) DEFAULT NULL,
                                 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单详情表';
CREATE TABLE `orders_item_2` (
                                 `id` bigint(11) NOT NULL   COMMENT '订单编号',
                                 `order_id` bigint(11) DEFAULT NULL COMMENT '订单编号',
                                 `user_id` int(16) DEFAULT NULL,
                                 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB   DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单详情表';
CREATE TABLE `orders_item_3` (
                                 `id` bigint(11) NOT NULL   COMMENT '订单编号',
                                 `order_id` bigint(11) DEFAULT NULL COMMENT '订单编号',
                                 `user_id` int(16) DEFAULT NULL,
                                 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='订单详情表';
BEGIN;
LOCK TABLES   `order_config` WRITE;
DELETE FROM   `order_config`;
UNLOCK TABLES;
COMMIT;
BEGIN;
LOCK TABLES   `orders_0` WRITE;
DELETE FROM   `orders_0`;
UNLOCK TABLES;
COMMIT;
BEGIN;
LOCK TABLES   `orders_2` WRITE;
DELETE FROM   `orders_2`;
INSERT INTO   `orders_2` (`id`,`user_id`) VALUES (495962620172435456, 2);
UNLOCK TABLES;
COMMIT;
BEGIN;
LOCK TABLES   `orders_item_0` WRITE;
DELETE FROM   `orders_item_0`;
UNLOCK TABLES;
COMMIT;
BEGIN;
LOCK TABLES   `orders_item_2` WRITE;
DELETE FROM   `orders_item_2`;
INSERT INTO   `orders_item_2` (`id`,`order_id`,`user_id`) VALUES (495972280044617728, 495962620172435456, 2),(495972281172885505, 495962620172435456, 2),(495972283899183104, 495962620172435456, 2);
UNLOCK TABLES;
COMMIT;

2. 配置文件

  • 说明:

① 区分于上面的GitHub两个数据库分别是1、3和0、2的表,在原来教程的基础上,使用的是两个数据库都是0、1、2、3的表。

② 因此,需要调整分片逻辑:

对分库保持 user_id % 2,对分表用 (user_id / 2) % 4}【注意:需要转换为int整数】

这样,奇数的userId在mall_1,偶数的在mall_0

③ 主键的生成策略

使用的雪花算法生成,解决分库分表的自增主键问题

④ 分库分表的维度

基于用户id,将其作为分片键

⑤ 配置步骤

首先,按照数据库配置,配置数据源(datasource)

其次,定义分片逻辑,定义特定的表【如果有默认的分片逻辑,也可以定义 default-table-strategy 】​

最后, 对每个表的分片逻辑主要包括表名、数据节点、主键生成策略、分库分表的表达式

⑥ 注意点

第一, mall-0,mall-1,不能用下划线,改为用 连字符

第二, 在分片时定义数据节点,表的名称是逻辑表名,数据节点是物理表,

第三,数据节点的库名需要为mall-0,而不是数据源url中的mall_0

server:
  port: 8080

# 线程池配置
thread:
  pool:
    executor:
      config:
        core-pool-size: 20
        max-pool-size: 50
        keep-alive-time: 5000
        block-queue-size: 5000
        policy: CallerRunsPolicy

# 数据库配置;启动时配置数据库资源信息
spring:
  shardingsphere:
    datasource:
      names: mall-0,mall-1
      # 数据源配置
      mall-0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/mall_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
        username: root
        password: 123456
      mall-1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/mall_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
        username: root
        password: 123456
    sharding:
      # 绑定表:分片规则一致的主表和子表
      binding-tables[0]: orders, orders_item
      tables:
        # orders 表配置
        orders:
          # mall-0的0,2两个表
          actualDataNodes: mall-0.orders_$->{[0,1,2,3]}, mall-1.orders_$->{[0,1,2,3]}
          # 主键生成策略:雪花算法
          key-generator:
            column: id
            type: SNOWFLAKE
          # 基于行表达式的分片策略
          database-strategy:
            inline:
              algorithm-expression: mall-$->{user_id % 2}
              sharding-column: user_id
          table-strategy:
            inline:
              sharding-column: user_id
              algorithm-expression: orders_$->{(int)(user_id / 2) % 4}

        # orders_item 表配置
        orders_item:
          actualDataNodes: mall-0.orders_item_$->{[0,1,2,3]}, mall-1.orders_item_$->{[0,1,2,3]}
          key-generator: # 主键生成策略:雪花算法
              column: id
              type: SNOWFLAKE
          database-strategy:
            inline:
              algorithm-expression: mall-$->{user_id % 2}
              sharding-column: user_id
          table-strategy:
            inline:
              sharding-column: user_id
              algorithm-expression: orders_item_$->{(int)(user_id/2) % 4}
        # order_config表配置:只有一个表
        order_config:
          actualDataNodes: mall-0.order_config
      #拓展属性配置
      props:
        sql:
          show: true



# MyBatis-Plus
mybatis-plus:
  configuration:
    #开启下划线转驼峰(列名到Java对象属性的转换:下划线 ->小驼峰)
    map-underscore-to-camel-case: true

3. 引入依赖

① JDK版本为1.8,springboot版本为2.7.1

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>question_answer_app_backend_2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>question_answer_app_backend_2</name>
    <description>question_answer_app_backend_2</description>
    <url/>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <mybaits-plus.version>3.5.2</mybaits-plus.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.7.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybaits-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-core</artifactId>
            <version>3.4.3.4</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.28</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

        <!-- 热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

        <!-- sharding-jdbc自动化配置 -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.1</version>
        </dependency>
        <!-- 阿里连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

4. 定义PO对象

跟数据库表中的po对应

package org.example.po;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("order_config")
public class OrderConfig {
    private Integer id;
    private Integer payTimeout;
}

package org.example.po;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("orders_item")
public class OrderItem {
    private Long id;
    private Long orderId;
    private Integer userId;
}
package org.example.po;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("orders")
public class Orders {
    private Long id;
    private Integer userId;
}

5. 定义Mapper

  • 定义mapper
package org.example.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.po.OrderConfig;
import org.springframework.stereotype.Component;
@Mapper
public interface OrderConfigMapper extends BaseMapper<OrderConfig> {
}
package org.example.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.po.OrderItem;
import org.springframework.stereotype.Component;

@Mapper
public interface OrderItemMapper extends BaseMapper<OrderItem> {

}
package org.example.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.dto.OrderItemJoinDTO;
import org.example.po.Orders;

import java.util.List;

@Mapper
public interface OrderMapper  extends BaseMapper<Orders> {
}

6. 定义controller

直接controller调用mapper测试。

package org.example.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.example.dto.OrderItemJoinDTO;
import org.example.mapper.OrderConfigMapper;
import org.example.mapper.OrderItemMapper;
import org.example.mapper.OrderMapper;
import org.example.po.OrderItem;
import org.example.po.Orders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;


@RestController
@Slf4j
public class TestController {
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private OrderItemMapper orderItemMapper;
@PostMapping("/testInsert")
@Transactional
    public void testInsert(){
        // 检查 Mapper 是否注入成功
        if (orderMapper == null || orderItemMapper == null) {
            log.error("Mapper injection failed: orderMapper={}, orderItemMapper={}", orderMapper, orderItemMapper);
            return;
        }
        // 测试插入订单和明细
        try{
            for (int userId = 11; userId <= 20; userId++) {
                Orders orders = new Orders();
                orders.setUserId(userId);
                orderMapper.insert(orders);
                log.info("insert order:{}", orders);
                OrderItem item = new OrderItem();
                item.setUserId(userId);
                item.setOrderId(orders.getId());
                orderItemMapper.insert(item);

                log.info("insert orderItem:{}",item);
            }
        }catch (Exception e){
            log.error("插入失败:{ }",e);
        }

    }
    @GetMapping("/testSelect")
    public  void testSelectByUserId(@RequestParam("userId") String userId){
        QueryWrapper<Orders> orderQueryWrapper = new QueryWrapper<>();
        orderQueryWrapper.eq("user_id",userId);
        Orders orders = orderMapper.selectOne(orderQueryWrapper);
        log.info("select order:{}", orders);
        QueryWrapper<OrderItem> itemQueryWrapper = new QueryWrapper<>();
        itemQueryWrapper.eq("user_id",userId).eq("order_id", orders.getId());
        OrderItem item = orderItemMapper.selectOne(itemQueryWrapper);
        log.info("select orderItem:{}",item);
    }
}

6. 测试

  • 启动项目

可以看到shardingsphere的配置

​在这里插入图片描述

  • 用IDEA的插件ApiFox测试

① 调用插入方法,插入的是10-20的userId。

​在这里插入图片描述
​

在数据库可以看到插入记录。与设置的分库分表逻辑相同。

16/2 = 8, 8%4=0,因此在orders_0表。

在这里插入图片描述
​

17/2取整得到 8, 8%4=0,因此在orders_0表。

​在这里插入图片描述
​

② 测试查询方法

此处的userId设置为数字类型,如果为字符串类型,可以对配置修改为取字符串的hashcode进行分片。

查询userId为17的记录,可以得到以下内容。

​在这里插入图片描述
​

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐