后端笔记09 | ShardingSphere+MyBatis-Plus分库分表代码实践
参考资料
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的记录,可以得到以下内容。

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


所有评论(0)