简单实现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]
相关推荐
BUG研究员_9 分钟前
LangChain 向量数据库实战:Redis 与 Pinecone 的知识点总结
数据库·redis·langchain
API快乐传递者18 分钟前
1688 跨境电商 API 接口实战指南:从寻源到代采的全链路技术方案
java·前端·数据库
孔明click3319 分钟前
不想写代码,但想要集成一个登录页面?Sa-Token-Quick-Login 帮你实现!
java·sa-token·开源·springboot·登录·权限·权限认证
曹牧32 分钟前
C#与Java后台交互
java·windows·microsoft·c#
张晓祥-长草颜团子34 分钟前
【重庆两江新区歌词】
java
东小西36 分钟前
【SAA实战】第 2 篇:模型与消息——ReactAgent 怎么挑模型、怎么传消息
java·后端·spring
LabVIEW开发40 分钟前
LabVIEW按段拆分TDMS文件的格式边界与重构
开发语言·数据库·重构·labview·labview知识·labview功能·labview程序
码匠许师傅1 小时前
【C++ 面试真题】35. 聊聊 C++ 的万能引用(T&&)和完美转发(std::forward)
java·c++·面试
程序员-Benothing1 小时前
什么是数据全量同步和增量同步?它们各有什么优缺点?
数据库
十年Java程序媛1 小时前
注解已经加上,但是事务没有回滚?拆解 AOP 代理底层原因 + 代码示例
java