1 摘要

随着业务数据的增加,单个的数据库已经无法支撑系统运行了,为了提升系统的流畅性,分库分表就是为了解决系统在大量数据情况下系统相应时间的问题。Sharding-jdbc 作为成熟的分库分表技术框架,在国内应用广泛。本文将介绍基于 Springboot 2.6 + Mybatis Plus 3.5 集成 Sharding-jdbc 5.1 实现分库分表功能。

Sharding-jdbc 官方文档: Use ShardingSphere Data Source in Spring

Sharding-jdbc 分库分表基本原理: 根据 id 进行取余,余数为多少,就对应相同编号的数据库、数据库表。

准备工作

数据库: 2个+

数据库表: 3个+

这里以最简分库分表为例: 一个单表(设备信息表),三张分表(路由器配置表)

./doc/sql/sharding_jdbc.sql
/*==============================================================*/
/* DBMS name:      MySQL 5.0                                    */
/* Created on:     2022/4/7 10:35:20                            */
/*==============================================================*/


DROP TABLE IF EXISTS DEVICE_INFO;

DROP TABLE IF EXISTS ROUTER_CONFIG_0;

DROP TABLE IF EXISTS ROUTER_CONFIG_1;

DROP TABLE IF EXISTS ROUTER_CONFIG_2;

/*==============================================================*/
/* Table: DEVICE_INFO                                           */
/*==============================================================*/
CREATE TABLE DEVICE_INFO
(
   ID                   BIGINT UNSIGNED NOT NULL COMMENT 'id',
   TYPE                 TINYINT COMMENT '设备类型,1-路由器,2-音响,3-摄像头',
   BRAND                VARCHAR(32) COMMENT '设备品牌',
   MODEL                VARCHAR(32) COMMENT '设备型号',
   NAME                 VARCHAR(32) COMMENT '设备名称',
   CREATE_TIME          DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
   UPDATE_TIME          DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
   PRIMARY KEY (ID)
)
ENGINE = INNODB DEFAULT
CHARSET = UTF8MB4;

ALTER TABLE DEVICE_INFO COMMENT '设备信息';

/*==============================================================*/
/* Table: ROUTER_CONFIG_0                                       */
/*==============================================================*/
CREATE TABLE ROUTER_CONFIG_0
(
   ID                   BIGINT UNSIGNED NOT NULL COMMENT '主键',
   DEVICE_ID            BIGINT COMMENT '设备id',
   WIFI_NAME            VARCHAR(32) COMMENT 'wifi名称',
   WIFI_PASSWORD        VARCHAR(64) COMMENT 'wifi密码',
   ENCRYPT_TYPE         TINYINT DEFAULT 0 COMMENT '加密类型,0-不加密,1-WPA-PSK,2-WPA2-PSK,3-WPA/WPA2-PSK',
   ADMIN_PASSWORD       VARCHAR(64) COMMENT '管理员密码',
   WIFI_SWITCH          TINYINT DEFAULT 1 COMMENT 'wifi开关,0-关闭,1-开启',
   HIDE_SWITCH          TINYINT DEFAULT 0 COMMENT '是否隐藏 wifi,0-不隐藏,1-隐藏',
   CREATE_TIME          DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
   UPDATE_TIME          DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
   PRIMARY KEY (ID)
)
ENGINE = INNODB DEFAULT
CHARSET = UTF8MB4;

ALTER TABLE ROUTER_CONFIG_0 COMMENT '路由器配置信息';

/*==============================================================*/
/* Table: ROUTER_CONFIG_1                                       */
/*==============================================================*/
CREATE TABLE ROUTER_CONFIG_1
(
   ID                   BIGINT UNSIGNED NOT NULL COMMENT '主键',
   DEVICE_ID            BIGINT COMMENT '设备id',
   WIFI_NAME            VARCHAR(32) COMMENT 'wifi名称',
   WIFI_PASSWORD        VARCHAR(64) COMMENT 'wifi密码',
   ENCRYPT_TYPE         TINYINT DEFAULT 0 COMMENT '加密类型,0-不加密,1-WPA-PSK,2-WPA2-PSK,3-WPA/WPA2-PSK',
   ADMIN_PASSWORD       VARCHAR(64) COMMENT '管理员密码',
   WIFI_SWITCH          TINYINT DEFAULT 1 COMMENT 'wifi开关,0-关闭,1-开启',
   HIDE_SWITCH          TINYINT DEFAULT 0 COMMENT '是否隐藏 wifi,0-不隐藏,1-隐藏',
   CREATE_TIME          DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
   UPDATE_TIME          DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
   PRIMARY KEY (ID)
)
ENGINE = INNODB DEFAULT
CHARSET = UTF8MB4;

ALTER TABLE ROUTER_CONFIG_1 COMMENT '路由器配置信息';

/*==============================================================*/
/* Table: ROUTER_CONFIG_2                                       */
/*==============================================================*/
CREATE TABLE ROUTER_CONFIG_2
(
   ID                   BIGINT UNSIGNED NOT NULL COMMENT '主键',
   DEVICE_ID            BIGINT COMMENT '设备id',
   WIFI_NAME            VARCHAR(32) COMMENT 'wifi名称',
   WIFI_PASSWORD        VARCHAR(64) COMMENT 'wifi密码',
   ENCRYPT_TYPE         TINYINT DEFAULT 0 COMMENT '加密类型,0-不加密,1-WPA-PSK,2-WPA2-PSK,3-WPA/WPA2-PSK',
   ADMIN_PASSWORD       VARCHAR(64) COMMENT '管理员密码',
   WIFI_SWITCH          TINYINT DEFAULT 1 COMMENT 'wifi开关,0-关闭,1-开启',
   HIDE_SWITCH          TINYINT DEFAULT 0 COMMENT '是否隐藏 wifi,0-不隐藏,1-隐藏',
   CREATE_TIME          DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
   UPDATE_TIME          DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
   PRIMARY KEY (ID)
)
ENGINE = INNODB DEFAULT
CHARSET = UTF8MB4;

ALTER TABLE ROUTER_CONFIG_2 COMMENT '路由器配置信息';

注意事项:

无论是分库还是分表,编号都要从 0 开始。数据源名称 ds0,ds1,表名 table_0,table_1 因为取余匹配数据库、表会出现余数为 0 的情况

2 Maven 核心依赖

./demo-sharding-jdbc/pom.xml
    <dependencies>
        <!-- web mvc -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${springboot.version}</version>
        </dependency>
        <!-- sharding-jdbc -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
            <version>${shardingsphere.version}</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- mybatis plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!-- hutool -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

其中对应的版本如下:

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <java.version>1.8</java.version>
        <springboot.version>2.6.6</springboot.version>
        <shardingsphere.version>5.1.0</shardingsphere.version>
        <mysql.version>8.0.28</mysql.version>
        <mybatis-plus.version>3.5.1</mybatis-plus.version>
        <hutool.version>5.7.21</hutool.version>

    </properties>

3 核心配置

3.1 公共配置
./demo-sharding-jdbc/src/main/resources/application.yml
## server
server:
  port: 8950

## spring
spring:
  application:
    name: demo-sharding-jdbc
  profiles:
    active: dev

## mybatis-plus
mybatis-plus:
  mapper-locations: classpath*:mybatis/*.xml
  type-aliases-package: com.ljq.demo.springboot.sharding.jdbc.model.entity
./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/common/MybatisPlusConfig.java
package com.ljq.demo.springboot.sharding.jdbc.common;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description: MybatisPlus 配置信息
 * @Author: junqiang.lu
 * @Date: 2020/9/1
 */
@Configuration
public class MybatisPlusConfig {

    /**
     * 新的分页插件,一缓和二缓遵循 mybatis 的规则
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}
3.2 只分表,不分库
./demo-sharding-jdbc/src/main/resources/application-dev.yml
## 不分库,分表

spring:
  shardingsphere:
    mode:
      type: Memory ## Sharding-jdbc 运行模式
    datasource:
      names: ds1  ## 数据源别名
      ds1:
        type: com.zaxxer.hikari.HikariDataSource  ## 数据源连接池连接类型,支持 Durid,Hikari 等常见数据库连接池
        driver-class-name: com.mysql.cj.jdbc.Driver  ## 数据库连接驱动
        jdbc-url: "jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8\
                    &useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8\
                    &useSSL=true&allowMultiQueries=true&autoReconnect=true&nullCatalogMeansCurrent=true"
        username: root
        password: "xxxx"
    rules:  ## 分库分表规则配置
      sharding:
        tables:
          router_config:  ## 数据库表名前缀
            actual-data-nodes: ds1.router_config_$->{0..2}  ## 实际表名
            table-strategy:  ## 分表策略
              standard:
                sharding-column: id  ## 按照分表的列
                sharding-algorithm-name: router-config-inline  ## 分表算法名称(使用 yml 配置不能包含下划线,否则不生效)
            key-generate-strategy:  ## 主键生成策略
              column: id  ## 主键列
              key-generator-name: snowflake  ## 策略算法名称(推荐使用雪花算法)
        sharding-algorithms:
          router-config-inline:
            type: INLINE
            props:
              algorithm-expression: router_config_$->{id % 3}  ## 分表算法(取余)
        key-generators:
          snowflake:
            type: SNOWFLAKE
    props:
      sql-show: true  ## 展示执行 SQL

官方配置说明:

在 Spring 中使用 ShardingSphere

3.3 分库,不分表
./demo-sharding-jdbc/src/main/resources/application-test.yml
## 分库,不分表

spring:
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: "jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8\
                    &useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8\
                    &useSSL=true&allowMultiQueries=true&autoReconnect=true&nullCatalogMeansCurrent=true"
        username: root
        password: "xxxx"
      ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: "jdbc:mysql://127.0.0.1:3306/demo2?useUnicode=true&characterEncoding=utf8\
                          &useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8\
                          &useSSL=true&allowMultiQueries=true&autoReconnect=true&nullCatalogMeansCurrent=true"
        username: root
        password: "xxxx"
    rules:
      sharding:
        default-database-strategy:
          standard:
            sharding-column: id
            sharding-algorithm-name: database-inline
        tables:
          device_info:  ## 数据库表名
            actual-data-nodes: ds$->{0..1}.device_info  ## 实际表节点
            key-generate-strategy:
              column: id
              key-generator-name: snowflake
        sharding-algorithms:
          database-inline:
            type: INLINE
            props:
              algorithm-expression: ds$->{id % 2}
        key-generators:
          snowflake:
            type: SNOWFLAKE
    props:
      sql-show: true
3.4 分库分表
./demo-sharding-jdbc/src/main/resources/application-prd.yml
## 分库,分表

spring:
  shardingsphere:
    mode:
      type: Standalone
      repository:
        type: File
      overwrite: true
    datasource:
      names: ds0,ds1
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: "jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8\
                    &useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8\
                    &useSSL=true&allowMultiQueries=true&autoReconnect=true&nullCatalogMeansCurrent=true"
        username: root
        password: "xxxx"
      ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: "jdbc:mysql://127.0.0.1:3306/demo2?useUnicode=true&characterEncoding=utf8\
                          &useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8\
                          &useSSL=true&allowMultiQueries=true&autoReconnect=true&nullCatalogMeansCurrent=true"
        username: root
        password: "xxxx"
    rules:
      sharding:
        default-database-strategy:
          standard:
            sharding-column: id
            sharding-algorithm-name: database-inline
        tables:
          router_config:
            actual-data-nodes: ds$->{0..1}.router_config_$->{0..2}
            table-strategy:
              standard:
                sharding-column: id
                sharding-algorithm-name: t-router-config-inline
            key-generate-strategy:
              column: id
              key-generator-name: snowflake
        sharding-algorithms:
          database-inline:
            type: INLINE
            props:
              algorithm-expression: ds$->{id % 2}
          t-router-config-inline:
            type: INLINE
            props:
              algorithm-expression: router_config_$->{id % 3}
        key-generators:
          snowflake:
            type: SNOWFLAKE
    props:
      sql-show: true

4 核心代码

4.1 实体类

基础实体类

./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/model/entity/BaseEntity.java
package com.ljq.demo.springboot.sharding.jdbc.model.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * @Description: 基础实体类
 * @Author: junqiang.lu
 * @Date: 2022/4/1
 */
@Data
public class BaseEntity implements Serializable {

    private static final long serialVersionUID = 2494094207811184245L;

    /**
     * id
     **/
    @JsonSerialize(using= ToStringSerializer.class)
    private Long id;
    /**
     * 创建时间
     **/
    @TableField(value = "CREATE_TIME")
    private Date createTime;
    /**
     * 更新时间
     **/
    @TableField(value = "UPDATE_TIME")
    private Date updateTime;


}

分表对应的实体类

./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/model/entity/RouterConfigEntity.java
package com.ljq.demo.springboot.sharding.jdbc.model.entity;

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

/**
 * @Description: 路由器配置实体
 * @Author: junqiang.lu
 * @Date: 2022/4/1
 */
@Data
@ToString(callSuper = true)
@TableName(value = "router_config")
public class RouterConfigEntity extends BaseEntity {

    private static final long serialVersionUID = 4849091384661358788L;

    /**
     * 设备 ID
     */
    private Long deviceId;
    /**
     * wifi 名称
     */
    private String wifiName;
    /**
     * wifi 密码
     */
    private String wifiPassword;
    /**
     * 加密类型,0-不加密,1-WPA-PSK,2-WPA2-PSK,3-WPA/WPA2-PSK
     */
    private Integer encryptType;
    /**
     * 管理员密码
     */
    private String adminPassword;
    /**
     * wifi开关,0-关闭,1-开启
     */
    private Integer wifiSwitch;
    /**
     * 是否隐藏 wifi,0-不隐藏,1-隐藏
     */
    private Integer hideSwitch;


}

注意事项:

对于分表的表名,使用逻辑表名,即实际表名包含编号,使用 Mybatis Plus 的 @TableName 不包含编号

只分库的数据库表对应的实体类

./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/model/entity/DeviceInfoEntity.java
package com.ljq.demo.springboot.sharding.jdbc.model.entity;

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

/**
 * @Description: 设备信息实体
 * @Author: junqiang.lu
 * @Date: 2022/4/1
 */
@Data
@ToString(callSuper = true)
@TableName(value = "device_info")
public class DeviceInfoEntity extends BaseEntity {

    private static final long serialVersionUID = -8417097323674970608L;

    /**
     * 设备类型,1-路由器,2-音响,3-摄像头
     */
    private Integer type;
    /**
     * 设备品牌
     */
    private String brand;
    /**
     * 设备型号
     */
    private String model;
    /**
     * 设备名称
     */
    private String name;


}

对于只分库的表名,和源库中的表名保持一致就可以

4.2 DAO 层

DAO 层按照正常 Mybatis Plus 写法

./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/dao/RouterConfigDao.java
package com.ljq.demo.springboot.sharding.jdbc.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ljq.demo.springboot.sharding.jdbc.model.entity.RouterConfigEntity;
import org.springframework.stereotype.Repository;

/**
 * @Description: 路由器配置 DAO
 * @Author: junqiang.lu
 * @Date: 2022/4/1
 */
@Repository
public interface RouterConfigDao extends BaseMapper<RouterConfigEntity> {


}
./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/dao/DeviceInfoDao.java
package com.ljq.demo.springboot.sharding.jdbc.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ljq.demo.springboot.sharding.jdbc.model.entity.DeviceInfoEntity;
import org.springframework.stereotype.Repository;

/**
 * @Description: 设备信息 DAO
 * @Author: junqiang.lu
 * @Date: 2022/4/1
 */
@Repository
public interface DeviceInfoDao extends BaseMapper<DeviceInfoEntity> {
}
4.3 Service 层

Service 接口

./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/service/RouterConfigService.java
package com.ljq.demo.springboot.sharding.jdbc.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ljq.demo.springboot.sharding.jdbc.model.entity.RouterConfigEntity;
import com.ljq.demo.springboot.sharding.jdbc.model.param.RouterConfigAddParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.RouterConfigQueryOneParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.RouterConfigQueryPageParam;

/**
 * @Description: 路由器配置业务接口
 * @Author: junqiang.lu
 * @Date: 2022/4/1
 */
public interface RouterConfigService {

    /**
     * 路由器配置新增
     *
     * @param addParam
     * @return
     */
    RouterConfigEntity add(RouterConfigAddParam addParam);

    /**
     * 路由器配置查询单条
     *
     * @param queryOneParam
     * @return
     */
    RouterConfigEntity queryOne(RouterConfigQueryOneParam queryOneParam);

    /**
     * 路由器配置分页查询
     *
     * @param queryPageParam
     * @return
     */
    IPage<RouterConfigEntity> queryPage(RouterConfigQueryPageParam queryPageParam);



}
./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/service/DeviceInfoService.java
package com.ljq.demo.springboot.sharding.jdbc.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ljq.demo.springboot.sharding.jdbc.model.entity.DeviceInfoEntity;
import com.ljq.demo.springboot.sharding.jdbc.model.param.DeviceInfoAddParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.DeviceInfoQueryOneParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.DeviceInfoQueryPageParam;

/**
 * @Description: 设备信息业务接口
 * @Author: junqiang.lu
 * @Date: 2022/4/1
 */
public interface DeviceInfoService {

    /**
     * 设备信息新增
     *
     * @param addParam
     * @return
     */
    DeviceInfoEntity add(DeviceInfoAddParam addParam);

    /**
     * 设备信息查询单条
     *
     * @param queryOneParam
     * @return
     */
    DeviceInfoEntity queryOne(DeviceInfoQueryOneParam queryOneParam);

    /**
     * 设备信息分页查询
     *
     * @param queryPageParam
     * @return
     */
    IPage<DeviceInfoEntity> queryPage(DeviceInfoQueryPageParam queryPageParam);
}

Service 实现类

Service 实现类和单数据源 Mybatis Plus 使用方式一致

./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/service/impl/RouterConfigServiceImpl.java
package com.ljq.demo.springboot.sharding.jdbc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ljq.demo.springboot.sharding.jdbc.dao.RouterConfigDao;
import com.ljq.demo.springboot.sharding.jdbc.model.entity.RouterConfigEntity;
import com.ljq.demo.springboot.sharding.jdbc.model.param.RouterConfigAddParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.RouterConfigQueryOneParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.RouterConfigQueryPageParam;
import com.ljq.demo.springboot.sharding.jdbc.service.RouterConfigService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;

/**
 * @Description: 路由器配置业务实现类
 * @Author: junqiang.lu
 * @Date: 2022/4/1
 */
@Service("routerConfigService")
public class RouterConfigServiceImpl extends ServiceImpl<RouterConfigDao, RouterConfigEntity>
        implements RouterConfigService {


    /**
     * 设备信息新增
     *
     * @param addParam
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    @Override
    public RouterConfigEntity add(RouterConfigAddParam addParam) {
        RouterConfigEntity routerConfigEntity = new RouterConfigEntity();
        BeanUtil.copyProperties(addParam, routerConfigEntity, CopyOptions.create().ignoreError().ignoreNullValue());
        this.save(routerConfigEntity);
        return routerConfigEntity;
    }

    /**
     * 设备信息查询单条
     *
     * @param queryOneParam
     * @return
     */
    @Override
    public RouterConfigEntity queryOne(RouterConfigQueryOneParam queryOneParam) {
        return this.getById(queryOneParam.getId());
    }

    /**
     * 设备信息分页查询
     *
     * @param queryPageParam
     * @return
     */
    @Override
    public IPage<RouterConfigEntity> queryPage(RouterConfigQueryPageParam queryPageParam) {
        IPage<RouterConfigEntity> page = new Page<>(queryPageParam.getCurrentPage(), queryPageParam.getPageSize());

        LambdaQueryWrapper<RouterConfigEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(Objects.nonNull(queryPageParam.getDeviceId()), RouterConfigEntity::getDeviceId,
                queryPageParam.getDeviceId());
        queryWrapper.orderBy(true,true,RouterConfigEntity::getId);
        return this.page(page, queryWrapper);
    }
}
./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/service/impl/DeviceInfoServiceImpl.java
package com.ljq.demo.springboot.sharding.jdbc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ljq.demo.springboot.sharding.jdbc.dao.DeviceInfoDao;
import com.ljq.demo.springboot.sharding.jdbc.model.entity.DeviceInfoEntity;
import com.ljq.demo.springboot.sharding.jdbc.model.param.DeviceInfoAddParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.DeviceInfoQueryOneParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.DeviceInfoQueryPageParam;
import com.ljq.demo.springboot.sharding.jdbc.service.DeviceInfoService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;

/**
 * @Description: 设备信息业务实现类
 * @Author: junqiang.lu
 * @Date: 2022/4/2
 */
@Service("deviceInfoService")
public class DeviceInfoServiceImpl extends ServiceImpl<DeviceInfoDao, DeviceInfoEntity> implements DeviceInfoService {


    /**
     * 设备信息新增
     *
     * @param addParam
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    @Override
    public DeviceInfoEntity add(DeviceInfoAddParam addParam) {
        DeviceInfoEntity  deviceInfoEntity = new DeviceInfoEntity();
        BeanUtil.copyProperties(addParam, deviceInfoEntity, CopyOptions.create().ignoreError().ignoreNullValue());
        this.save(deviceInfoEntity);
        return deviceInfoEntity;
    }

    /**
     * 设备信息查询单条
     *
     * @param queryOneParam
     * @return
     */
    @Override
    public DeviceInfoEntity queryOne(DeviceInfoQueryOneParam queryOneParam) {
        return this.getById(queryOneParam.getId());
    }

    /**
     * 设备信息分页查询
     *
     * @param queryPageParam
     * @return
     */
    @Override
    public IPage<DeviceInfoEntity> queryPage(DeviceInfoQueryPageParam queryPageParam) {
        Page<DeviceInfoEntity> page = new Page<>(queryPageParam.getCurrentPage(), queryPageParam.getPageSize());
        LambdaQueryWrapper<DeviceInfoEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(Objects.nonNull(queryPageParam.getType()), DeviceInfoEntity::getType, queryPageParam.getType());
        queryWrapper.orderBy(true, true, DeviceInfoEntity::getType);
        return this.page(page, queryWrapper);
    }
}
4.4 控制层
./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/controller/RouterConfigController.java
package com.ljq.demo.springboot.sharding.jdbc.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ljq.demo.springboot.sharding.jdbc.model.entity.RouterConfigEntity;
import com.ljq.demo.springboot.sharding.jdbc.model.param.RouterConfigAddParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.RouterConfigQueryOneParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.RouterConfigQueryPageParam;
import com.ljq.demo.springboot.sharding.jdbc.service.RouterConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

/**
 * @Description: 路由器配置控制层
 * @Author: junqiang.lu
 * @Date: 2022/4/1
 */
@RestController
@RequestMapping(value = "/api/sharding/jdbc/router/config")
public class RouterConfigController {

    @Autowired
    private RouterConfigService routerConfigService;

    /**
     * 路由器配置新增单条
     *
     * @param addParam
     * @return
     */
    @PostMapping(value = "/add", produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<RouterConfigEntity> add(@RequestBody RouterConfigAddParam addParam) {
        return ResponseEntity.ok(routerConfigService.add(addParam));
    }

    /**
     * 路由器配置查询单条
     *
     * @param queryOneParam
     * @return
     */
    @GetMapping(value = "/query/one", produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<RouterConfigEntity> queryOne(RouterConfigQueryOneParam queryOneParam) {
        return ResponseEntity.ok(routerConfigService.queryOne(queryOneParam));
    }

    /**
     * 路由器配置分页查询
     *
     * @param queryPageParam
     * @return
     */
    @GetMapping(value = "/query/page", produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<IPage<RouterConfigEntity>> queryPage(RouterConfigQueryPageParam queryPageParam) {
        return ResponseEntity.ok(routerConfigService.queryPage(queryPageParam));
    }


}
./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/controller/DeviceInfoController.java
package com.ljq.demo.springboot.sharding.jdbc.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ljq.demo.springboot.sharding.jdbc.model.entity.DeviceInfoEntity;
import com.ljq.demo.springboot.sharding.jdbc.model.param.DeviceInfoAddParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.DeviceInfoQueryOneParam;
import com.ljq.demo.springboot.sharding.jdbc.model.param.DeviceInfoQueryPageParam;
import com.ljq.demo.springboot.sharding.jdbc.service.DeviceInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

/**
 * @Description: 设备信息控制层
 * @Author: junqiang.lu
 * @Date: 2022/4/2
 */
@RestController
@RequestMapping(value = "/api/sharding/jdbc/device")
public class DeviceInfoController {

    @Autowired
    private DeviceInfoService deviceInfoService;

    /**
     * 设备信息新增单条
     *
     * @param addParam
     * @return
     */
    @PostMapping(value = "/add", produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<DeviceInfoEntity> add(@RequestBody DeviceInfoAddParam addParam) {
        return ResponseEntity.ok(deviceInfoService.add(addParam));
    }

    /**
     * 设备信息查询单条
     *
     * @param queryOneParam
     * @return
     */
    @GetMapping(value = "/query/one", produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<DeviceInfoEntity> queryOne(DeviceInfoQueryOneParam queryOneParam) {
        return ResponseEntity.ok(deviceInfoService.queryOne(queryOneParam));
    }

    /**
     * 设备信息分页查询
     *
     * @param queryPageParam
     * @return
     */
    @GetMapping(value = "/query/page", produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<IPage<DeviceInfoEntity>> queryPage(DeviceInfoQueryPageParam queryPageParam) {
        return ResponseEntity.ok(deviceInfoService.queryPage(queryPageParam));
    }

}
4.5 SpringBoot 启动类
./demo-sharding-jdbc/src/main/java/com/ljq/demo/springboot/sharding/jdbc/DemoShardingJdbcApplication.java
package com.ljq.demo.springboot.sharding.jdbc;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author lujunqiang
 */
@MapperScan(basePackages = {"com.ljq.demo.springboot.sharding.jdbc.dao"})
@SpringBootApplication
public class DemoShardingJdbcApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoShardingJdbcApplication.class, args);
    }

}

5 测试

5.1 只分表,不分库
5.1.1 插入数据

分表请求接口:

http://127.0.0.1:8950/api/sharding/jdbc/router/config/add

请求方式: POST

请求参数:

{
    "deviceId": "1",
    "wifiName": "Lexus",
    "wifiPassword": "OGBFs9Ksa2E0m8M",
    "encryptType": 1,
    "adminPassword": "vbo7u3kgPeFJYU6",
    "wifiSwitch": 1,
    "hideSwitch": 1
}

后台日志:

2022-04-12 19:18:36.781  INFO 21080 --- [nio-8950-exec-2] ShardingSphere-SQL                       : Logic SQL: INSERT INTO router_config  ( id,
device_id,
wifi_name,
wifi_password,
encrypt_type,
admin_password,
wifi_switch,
hide_switch )  VALUES  ( ?,
?,
?,
?,
?,
?,
?,
? )
2022-04-12 19:18:36.781  INFO 21080 --- [nio-8950-exec-2] ShardingSphere-SQL                       : SQLStatement: MySQLInsertStatement(setAssignment=Optional.empty, onDuplicateKeyColumns=Optional.empty)
2022-04-12 19:18:36.781  INFO 21080 --- [nio-8950-exec-2] ShardingSphere-SQL                       : Actual SQL: ds1 ::: INSERT INTO router_config_2  ( id,
device_id,
wifi_name,
wifi_password,
encrypt_type,
admin_password,
wifi_switch,
hide_switch )  VALUES  (?, ?, ?, ?, ?, ?, ?, ?) ::: [1513838994770907137, 1, Lexus, OGBFs9Ksa2E0m8M, 1, vbo7u3kgPeFJYU6, 1, 1]

从日志可以看出,SQL 分为逻辑 SQL 以及实际执行的 SQL ,根据 id 取余,最终插入的表为 router_config_2

对比没有分表的数据插入

请求接口:

http://127.0.0.1:8950/api/sharding/jdbc/device/add

请求方式: POST

请求参数:

{
    "type": 1,
    "brand": "TP-LINK",
    "model": "TL-WDR5620",
    "name": "TP-LINK双频千兆路由169"
}

后台日志:

2022-04-12 19:22:13.147  INFO 21080 --- [nio-8950-exec-3] ShardingSphere-SQL                       : Logic SQL: INSERT INTO device_info  ( id,
type,
brand,
model,
name )  VALUES  ( ?,
?,
?,
?,
? )
2022-04-12 19:22:13.147  INFO 21080 --- [nio-8950-exec-3] ShardingSphere-SQL                       : SQLStatement: MySQLInsertStatement(setAssignment=Optional.empty, onDuplicateKeyColumns=Optional.empty)
2022-04-12 19:22:13.147  INFO 21080 --- [nio-8950-exec-3] ShardingSphere-SQL                       : Actual SQL: ds1 ::: INSERT INTO device_info  ( id,
type,
brand,
model,
name )  VALUES  (?, ?, ?, ?, ?) ::: [1513839902246326273, 1, TP-LINK, TL-WDR5620, TP-LINK双频千兆路由169]

从日志可以看出,实际执行SQL与逻辑SQL一致,对于同一数据库中不分表的数据库表,SQL 执行不受影响

5.1.2 查询单条

分表请求接口:

http://127.0.0.1:8950/api/sharding/jdbc/router/config/query/one?id=1510093606222135297

请求方式: GET

后台日志:

2022-04-12 19:24:19.691  INFO 21080 --- [nio-8950-exec-6] ShardingSphere-SQL                       : Logic SQL: SELECT id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME FROM router_config WHERE id=? 
2022-04-12 19:24:19.691  INFO 21080 --- [nio-8950-exec-6] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2022-04-12 19:24:19.691  INFO 21080 --- [nio-8950-exec-6] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME FROM router_config_1 WHERE id=?  ::: [1510093606222135297]

从日志可以看出,也是根据 id 值先确定表,再执行查询

5.1.3 分页查询

分表请求接口:

http://127.0.0.1:8950/api/sharding/jdbc/router/config/query/page?currentPage=1&pageSize=10&deviceId=1

请求方式: GET

后台日志:

2022-04-12 19:27:52.471  INFO 21080 --- [nio-8950-exec-8] ShardingSphere-SQL                       : Logic SQL: SELECT COUNT(*) AS total FROM router_config WHERE (device_id = ?)
2022-04-12 19:27:52.471  INFO 21080 --- [nio-8950-exec-8] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2022-04-12 19:27:52.471  INFO 21080 --- [nio-8950-exec-8] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT COUNT(*) AS total FROM router_config_0 WHERE (device_id = ?) UNION ALL SELECT COUNT(*) AS total FROM router_config_1 WHERE (device_id = ?) UNION ALL SELECT COUNT(*) AS total FROM router_config_2 WHERE (device_id = ?) ::: [1, 1, 1]
2022-04-12 19:27:52.653  INFO 21080 --- [nio-8950-exec-8] ShardingSphere-SQL                       : Logic SQL: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ?
2022-04-12 19:27:52.653  INFO 21080 --- [nio-8950-exec-8] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional[org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.LimitSegment@5ac88e33], lock=Optional.empty, window=Optional.empty)
2022-04-12 19:27:52.653  INFO 21080 --- [nio-8950-exec-8] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config_0 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ? ::: [1, 10]
2022-04-12 19:27:52.653  INFO 21080 --- [nio-8950-exec-8] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config_1 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ? ::: [1, 10]
2022-04-12 19:27:52.654  INFO 21080 --- [nio-8950-exec-8] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config_2 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ? ::: [1, 10]

从日志可以看出,实际执行的SQL是根据分表的数量执行了多次,然后将每个分表的查询结果聚合

5.2 只分库,不分表
5.2.1 插入数据

请求接口:

http://127.0.0.1:8950/api/sharding/jdbc/device/add

请求方式: POST

请求参数:

{
    "type": 1,
    "brand": "TP-LINK",
    "model": "TL-WDR5620",
    "name": "TP-LINK双频千兆路由992"
}

后台日志:

2022-04-12 19:33:43.878  INFO 15896 --- [nio-8950-exec-4] ShardingSphere-SQL                       : Logic SQL: INSERT INTO device_info  ( id,
type,
brand,
model,
name )  VALUES  ( ?,
?,
?,
?,
? )
2022-04-12 19:33:43.879  INFO 15896 --- [nio-8950-exec-4] ShardingSphere-SQL                       : SQLStatement: MySQLInsertStatement(setAssignment=Optional.empty, onDuplicateKeyColumns=Optional.empty)
2022-04-12 19:33:43.879  INFO 15896 --- [nio-8950-exec-4] ShardingSphere-SQL                       : Actual SQL: ds1 ::: INSERT INTO device_info  ( id,
type,
brand,
model,
name )  VALUES  (?, ?, ?, ?, ?) ::: [1513842798769786881, 1, TP-LINK, TL-WDR5620, TP-LINK双频千兆路由992]

日志中可以看出数据实际插入的数据库是根据 id 进行取余,然后得到的余数即为数据库的编码

5.2.2 查询单条

请求接口:

http://127.0.0.1:8950/api/sharding/jdbc/device/query/one?id=1511636056593956866

请求方式: GET

后台日志:

2022-04-12 19:39:31.695  INFO 15896 --- [nio-8950-exec-3] ShardingSphere-SQL                       : Logic SQL: SELECT id,type,brand,model,name,CREATE_TIME,UPDATE_TIME FROM device_info WHERE id=? 
2022-04-12 19:39:31.695  INFO 15896 --- [nio-8950-exec-3] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2022-04-12 19:39:31.695  INFO 15896 --- [nio-8950-exec-3] ShardingSphere-SQL                       : Actual SQL: ds0 ::: SELECT id,type,brand,model,name,CREATE_TIME,UPDATE_TIME FROM device_info WHERE id=?  ::: [1511636056593956866]
5.2.3 分页查询

请求接口:

http://127.0.0.1:8950/api/sharding/jdbc/device/query/page?currentPage=1&pageSize=10&type=1

请求方式: GET

后台日志:

2022-04-12 20:10:29.920  INFO 15896 --- [nio-8950-exec-7] ShardingSphere-SQL                       : Logic SQL: SELECT COUNT(*) AS total FROM device_info WHERE (type = ?)
2022-04-12 20:10:29.920  INFO 15896 --- [nio-8950-exec-7] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2022-04-12 20:10:29.920  INFO 15896 --- [nio-8950-exec-7] ShardingSphere-SQL                       : Actual SQL: ds0 ::: SELECT COUNT(*) AS total FROM device_info WHERE (type = ?) ::: [1]
2022-04-12 20:10:29.920  INFO 15896 --- [nio-8950-exec-7] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT COUNT(*) AS total FROM device_info WHERE (type = ?) ::: [1]
2022-04-12 20:10:30.196  INFO 15896 --- [nio-8950-exec-7] ShardingSphere-SQL                       : Logic SQL: SELECT  id,type,brand,model,name,CREATE_TIME,UPDATE_TIME  FROM device_info 
 
 WHERE (type = ?) ORDER BY type ASC LIMIT ?
2022-04-12 20:10:30.196  INFO 15896 --- [nio-8950-exec-7] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional[org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.LimitSegment@61585c7f], lock=Optional.empty, window=Optional.empty)
2022-04-12 20:10:30.196  INFO 15896 --- [nio-8950-exec-7] ShardingSphere-SQL                       : Actual SQL: ds0 ::: SELECT  id,type,brand,model,name,CREATE_TIME,UPDATE_TIME  FROM device_info 
 
 WHERE (type = ?) ORDER BY type ASC LIMIT ? ::: [1, 10]
2022-04-12 20:10:30.196  INFO 15896 --- [nio-8950-exec-7] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT  id,type,brand,model,name,CREATE_TIME,UPDATE_TIME  FROM device_info 
 
 WHERE (type = ?) ORDER BY type ASC LIMIT ? ::: [1, 10]

从执行语句可以看出,是先将每个数据库查询数据总条数查询出来,然后再分页查询每个数据库的数据,最后进行汇总

5.3 分库分表
5.3.1 插入数据

请求接口:

http://127.0.0.1:8950/api/sharding/jdbc/router/config/add

请求方式: POST

请求参数:

{
    "deviceId": "1",
    "wifiName": "Zoie",
    "wifiPassword": "oWCRA6nfduiWZNi",
    "encryptType": 1,
    "adminPassword": "__2Z4NG6xvhpEQY",
    "wifiSwitch": 1,
    "hideSwitch": 1
}

后台日志:

2022-04-12 20:13:47.488  INFO 20788 --- [nio-8950-exec-2] ShardingSphere-SQL                       : Logic SQL: INSERT INTO router_config  ( id,
device_id,
wifi_name,
wifi_password,
encrypt_type,
admin_password,
wifi_switch,
hide_switch )  VALUES  ( ?,
?,
?,
?,
?,
?,
?,
? )
2022-04-12 20:13:47.489  INFO 20788 --- [nio-8950-exec-2] ShardingSphere-SQL                       : SQLStatement: MySQLInsertStatement(setAssignment=Optional.empty, onDuplicateKeyColumns=Optional.empty)
2022-04-12 20:13:47.489  INFO 20788 --- [nio-8950-exec-2] ShardingSphere-SQL                       : Actual SQL: ds1 ::: INSERT INTO router_config_2  ( id,
device_id,
wifi_name,
wifi_password,
encrypt_type,
admin_password,
wifi_switch,
hide_switch )  VALUES  (?, ?, ?, ?, ?, ?, ?, ?) ::: [1513852877632000001, 1, Zoie, oWCRA6nfduiWZNi, 1, __2Z4NG6xvhpEQY, 1, 1]

从执行SQL可以看出数据库、数据库表都是经过id取余计算后得到的

5.3.2 请求单条

请求接口:

http://127.0.0.1:8950/api/sharding/jdbc/router/config/query/one?id=1510093606222135297

请求方式: GET

请求日志:

2022-04-12 20:16:11.335  INFO 20788 --- [nio-8950-exec-3] ShardingSphere-SQL                       : Logic SQL: SELECT id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME FROM router_config WHERE id=? 
2022-04-12 20:16:11.335  INFO 20788 --- [nio-8950-exec-3] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2022-04-12 20:16:11.335  INFO 20788 --- [nio-8950-exec-3] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME FROM router_config_1 WHERE id=?  ::: [1510093606222135297]
5.3.3 分页查询

请求接口:

http://127.0.0.1:8950/api/sharding/jdbc/router/config/query/page?currentPage=1&pageSize=10&deviceId=1

请求方式: GET

后台日志:

2022-04-12 20:18:03.387  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : Logic SQL: SELECT COUNT(*) AS total FROM router_config WHERE (device_id = ?)
2022-04-12 20:18:03.387  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2022-04-12 20:18:03.387  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : Actual SQL: ds0 ::: SELECT COUNT(*) AS total FROM router_config_0 WHERE (device_id = ?) UNION ALL SELECT COUNT(*) AS total FROM router_config_1 WHERE (device_id = ?) UNION ALL SELECT COUNT(*) AS total FROM router_config_2 WHERE (device_id = ?) ::: [1, 1, 1]
2022-04-12 20:18:03.387  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT COUNT(*) AS total FROM router_config_0 WHERE (device_id = ?) UNION ALL SELECT COUNT(*) AS total FROM router_config_1 WHERE (device_id = ?) UNION ALL SELECT COUNT(*) AS total FROM router_config_2 WHERE (device_id = ?) ::: [1, 1, 1]
2022-04-12 20:18:03.633  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : Logic SQL: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ?
2022-04-12 20:18:03.633  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional[org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.LimitSegment@2fc3d159], lock=Optional.empty, window=Optional.empty)
2022-04-12 20:18:03.633  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : Actual SQL: ds0 ::: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config_0 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ? ::: [1, 10]
2022-04-12 20:18:03.633  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : Actual SQL: ds0 ::: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config_1 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ? ::: [1, 10]
2022-04-12 20:18:03.633  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : Actual SQL: ds0 ::: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config_2 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ? ::: [1, 10]
2022-04-12 20:18:03.633  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config_0 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ? ::: [1, 10]
2022-04-12 20:18:03.633  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config_1 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ? ::: [1, 10]
2022-04-12 20:18:03.634  INFO 20788 --- [nio-8950-exec-5] ShardingSphere-SQL                       : Actual SQL: ds1 ::: SELECT  id,device_id,wifi_name,wifi_password,encrypt_type,admin_password,wifi_switch,hide_switch,CREATE_TIME,UPDATE_TIME  FROM router_config_2 
 
 WHERE (device_id = ?) ORDER BY id ASC LIMIT ? ::: [1, 10]

分库分表的分页查询相对复杂一些,会先将同一个数据库中的多个分表数据联合查询,得到单库总条数,然后再汇总所有分库数据得到总的数据条数;每一个分库中的每一个分表都执行一条分页查询SQL,得到分页结果,最后将所有的结果聚合返回

6 推荐参考资料

Use ShardingSphere Data Source in Spring

ShardingSphere-example 官方示例

shardingsphere 5.0控制台输出sql语句

【Sharding-JDBC】(一) 整合mybatis-plus 水平分表

7 Github 源码

Gtihub 源码地址 : https://github.com/Flying9001/springBootDemo

个人公众号:404Code,分享半个互联网人的技术与思考,感兴趣的可以关注.
404Code

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐