简单实现shardingSphere + MybatisPlus分库分表2025

shardingSphere分库分表简单实现

准备

环境

  • mysql 5.7 +
  • Springboot 3.2 +
  • mybatis-plus 3.5.5
  • druid 1.2.23
  • shardingsphere-jdbc 5.5
  • JDK 21

Pom

xml 复制代码
<dependencies>
    <!-- Spring Boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        <version>3.5.5</version>
    </dependency>

    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.23</version>
    </dependency>

    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>shardingsphere-jdbc</artifactId>
        <version>5.5.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.apache.shardingsphere</groupId>
                <artifactId>shardingsphere-test-util</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.alibaba.fastjson2</groupId>
        <artifactId>fastjson2</artifactId>
        <version>2.0.54</version>
    </dependency>
</dependencies>

数据库准备

新建两个库、分别建四张表

sql 复制代码
CREATE DATABASE `order_db_0` /*!40100 DEFAULT CHARACTER SET utf8 */;
CREATE DATABASE `order_db_1` /*!40100 DEFAULT CHARACTER SET utf8 */;

CREATE TABLE `order_0` (
  `order_id` bigint(20) NOT NULL,
  `user_id` bigint(20) NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`order_id`),
  KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 其他四张表结构一致即可

代码部分

配置文件

在resource目录下新建两个文件:

application.yaml

yaml 复制代码
spring:
  main:
    allow-bean-definition-overriding: true
  application:
    name: ls-backend
  datasource:
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
    url: jdbc:shardingsphere:classpath:sharding.yaml
  servlet:
    multipart:
      max-file-size: 100MB
      max-request-size: 100MB
server:
  port: 8085
  servlet:
    context-path: /
    encoding:
      force-response: true


#Mybatis扫描
mybatis:
  config-location: classpath:/mybatis-config.xml

mybatis-plus:
  mapper-locations: classpath:/mapper/*Mapper.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

sharding.yaml

yaml 复制代码
dataSources:
  ds0:
    driverClassName: com.mysql.cj.jdbc.Driver
    dataSourceClassName: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://xxx
    username: test
    password: test
  ds1:
    driverClassName: com.mysql.cj.jdbc.Driver
    dataSourceClassName: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://yyy
    username: test
    password: test



rules:
  - !SHARDING
    tables:
      order:
        actualDataNodes: ds${0..1}.order_${0..3}
        tableStrategy:
          standard:
            shardingColumn: order_id
            shardingAlgorithmName: order-id-inline
        databaseStrategy:
          standard:
            shardingColumn: user_id
            shardingAlgorithmName: db-inline
    bindingTables:
      - order
    shardingAlgorithms:
      db-inline:
        type: INLINE
        props:
          algorithm-expression: ds${user_id % 2}
      order-id-inline:
        type: INLINE
        props:
          algorithm-expression: order_${order_id % 4}


props:
  sql-show: true

实体类

java 复制代码
@Data
@TableName("`order`") // MyBatis-Plus 表名(与分片表名一致)
public class Order {
    @TableId(type = IdType.ASSIGN_ID) // 手动输入主键(由雪花算法生成)
    private Long orderId; 
    private Long userId;
    private BigDecimal amount;
    private LocalDateTime createTime;
}

Mapper

java 复制代码
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}

Service

java 复制代码
@Service
@Slf4j
public class OrderService {


    @Autowired
    private OrderMapper orderMapper;

    @Transactional
    public int createOrder(Long userId, BigDecimal amount) {
        SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);

        Order order = new Order();
        order.setOrderId(generator.nextId()); // 自动生成 BIGINT 类型的雪花 ID
        order.setUserId(userId);
        order.setAmount(amount);
        log.info("即将插入的order: {}", JSON.toJSONString(order));
        // MyBatis-Plus 插入
        return orderMapper.insert(order);
    }

    public List<Order> getOrderById(Long orderId, Long userId) {
        log.info("查询订单,orderId: {}", orderId);
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.eq("order_id", orderId);
        return orderMapper.selectList(wrapper);
    }
}

雪花算法工具

java 复制代码
public class SnowflakeIdGenerator {
    // 起始时间戳(2024-01-01 00:00:00)
    private static final long TWEPOCH = 1704067200000L;

    // 工作机器 ID(10位,范围:0~1023)
    private final long workerId;

    // 数据中心 ID(10位中的高位,范围:0~1023)
    private final long datacenterId;

    // 序列号(12位,范围:0~4095)
    private long sequence = 0L;

    // 上次生成 ID 的时间戳(毫秒)
    private long lastTimestamp = -1L;

    /**
     * 构造函数(需指定唯一的工作机器 ID 和数据中心 ID)
     * @param workerId 工作机器 ID(0~1023)
     * @param datacenterId 数据中心 ID(0~1023)
     */
    public SnowflakeIdGenerator(long workerId, long datacenterId) {
        // 校验参数范围
        if (workerId > 1023 || workerId < 0) {
            throw new IllegalArgumentException("Worker ID must be between 0 and 1023");
        }
        if (datacenterId > 1023 || datacenterId < 0) {
            throw new IllegalArgumentException("Datacenter ID must be between 0 and 1023");
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    /**
     * 生成下一个 ID
     * @return 64位 BIGINT 类型的雪花算法 ID
     */
    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();

        // 处理时间戳回拨(可选)
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate ID");
        }

        // 同一毫秒内生成多个 ID
        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & 0xFFF; // 12位掩码(0~4095)
            if (sequence == 0) { // 序列号溢出,等待下一毫秒
                timestamp = waitNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L; // 新毫秒,序列号重置
        }

        lastTimestamp = timestamp;

        // 计算 ID(按位拼接)
        return ((timestamp - TWEPOCH) << 22) // 时间戳(41位)
                | (datacenterId << 17)       // 数据中心 ID(5位)
                | (workerId << 12)           // 工作机器 ID(5位)
                | sequence;                  // 序列号(12位)
    }

    /**
     * 等待下一毫秒(解决同一毫秒内序列号溢出)
     */
    private long waitNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    // 测试示例
    public static void main(String[] args) {
        // 示例:工作机器 ID=1,数据中心 ID=1(需根据实际环境调整)
        SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);
        for (int i = 0; i < 10; i++) {
            System.out.println("Generated ID: " + generator.nextId());
        }
    }
}

实测

创建

bash 复制代码
 INFO 35088 --- [ls-backend] [nio-8085-exec-1] ShardingSphere-SQL                       : Logic SQL: INSERT INTO `order`  ( order_id, user_id, amount )  VALUES (  ?, ?, ?  )
INFO 35088 --- [ls-backend] [nio-8085-exec-1] ShardingSphere-SQL                       : Actual SQL: ds1 ::: INSERT INTO `order_0`  ( order_id, user_id, amount )  VALUES (?, ?, ?) ::: [191145194425552896, 987654321095, 8]

查询

bash 复制代码
INFO 35088 --- [ls-backend] [nio-8085-exec-3] ShardingSphere-SQL                       : Logic SQL: SELECT  order_id,user_id,amount,create_time  FROM `order`      WHERE  (user_id = ? AND order_id = ?)
INFO 35088 --- [ls-backend] [nio-8085-exec-3] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT  order_id,user_id,amount,create_time  FROM `order_0`      WHERE  (user_id = ? AND order_id = ?) ::: [987654321095, 191145194425552896]
相关推荐
武子康1 小时前
Java-80 深入浅出 RPC Dubbo 动态服务降级:从雪崩防护到配置中心秒级生效
java·分布式·后端·spring·微服务·rpc·dubbo
-SGlow-3 小时前
MySQL相关概念和易错知识点(2)(表结构的操作、数据类型、约束)
linux·运维·服务器·数据库·mysql
明月5664 小时前
Oracle 误删数据恢复
数据库·oracle
YuTaoShao4 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
源码_V_saaskw4 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友
超浪的晨4 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
双力臂4045 小时前
Spring Boot 单元测试进阶:JUnit5 + Mock测试与切片测试实战及覆盖率报告生成
java·spring boot·后端·单元测试
♡喜欢做梦5 小时前
【MySQL】深入浅出事务:保证数据一致性的核心武器
数据库·mysql
遇见你的雩风5 小时前
MySQL的认识与基本操作
数据库·mysql
Edingbrugh.南空5 小时前
Aerospike与Redis深度对比:从架构到性能的全方位解析
java·开发语言·spring