sharding5.0.0分表分库

sharding官网参考

https://shardingsphere.apache.org/document/current/cn/overview/

https://shardingsphere.apache.org/document/legacy/4.x/document/cn/features/sharding/use-norms/pagination/

 https://shardingsphere.apache.org/document/legacy/4.x/document/cn/downloads/#%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC

https://shardingsphere.apache.org/document/5.0.0/cn/features/sharding/

优秀文章参考

ShardingSphere-JDBC - YAML 配置 - 《Apache ShardingSphere v5.1.0 中文文档》 - 书栈网 · BookStack

 https://www.cnblogs.com/xfeiyun/p/16185727.html

 ShardingJDBC-5.0.0及4.0.0使用示例_sharding-jdbc 5._红石丶的博客-CSDN博客

引言:

sharding各个版本相对而言不能配置都有差异,而sharding5.0.0.0相对而言是比较新的,网上相关的资料少的可怜,参考了非常多的文章写下demo,供大家参考

集成

1 当前使用shardingsphere-jdbc-core-spring-boot-starter 5.0.0版本

 
        
            com.baomidou
            dynamic-datasource-spring-boot-starter
            ${dynamic-datasource-spring-boot-starter.version}
        
        
        
            org.apache.shardingsphere
            shardingsphere-jdbc-core-spring-boot-starter
            5.0.0
        

 因为数据源之前框架已经有druild,为了不影响之前的框架数据源配置,增加动态多数据源

package org.jeecg.boot.shardingsphere.config;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Map;

/**
 * 分库分表数据源配置
 * @author zyf
 */
@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
public class DataSourceConfiguration {
    /**
     * 分表数据源名称
     */
    public static final String SHARDING_DATA_SOURCE_NAME = "sharding";
    /**
     * 动态数据源配置项
     */
    @Resource
    private DynamicDataSourceProperties dynamicDataSourceProperties;

    @Lazy
    @Resource
    DataSource shardingDataSource;

    /**
     * 将shardingDataSource放到了多数据源(dataSourceMap)中
     * 注意有个版本的bug,3.1.1版本 不会进入loadDataSources 方法,这样就一直造成数据源注册失败
     */
    @Bean
    public DynamicDataSourceProvider dynamicDataSourceProvider() {
        Map datasourceMap = dynamicDataSourceProperties.getDatasource();
        return new AbstractDataSourceProvider() {
            @Override
            public Map loadDataSources() {
                Map dataSourceMap = createDataSourceMap(datasourceMap);
                // 将 shardingjdbc 管理的数据源也交给动态数据源管理
                dataSourceMap.put(SHARDING_DATA_SOURCE_NAME, shardingDataSource);
                return dataSourceMap;
            }
        };
    }

    /**
     * 将动态数据源设置为首选的
     * 当spring存在多个数据源时, 自动注入的是首选的对象
     * 设置为主要的数据源之后,就可以支持shardingjdbc原生的配置方式了
     *
     * @return
     */
    @Primary
    @Bean
    public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
        DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
        dataSource.setPrimary(dynamicDataSourceProperties.getPrimary());
        dataSource.setStrict(dynamicDataSourceProperties.getStrict());
        dataSource.setStrategy(dynamicDataSourceProperties.getStrategy());
        dataSource.setProvider(dynamicDataSourceProvider);
        dataSource.setP6spy(dynamicDataSourceProperties.getP6spy());
        dataSource.setSeata(dynamicDataSourceProperties.getSeata());
        return dataSource;
    }
}

 2 项目结构

 sharding5.0.0分表分库_第1张图片

 3 初始化sql


#1按照年月范围分表sql
CREATE TABLE `t_order_2020_6` (
                                  `id` bigint(20) NOT NULL COMMENT '主键',
                                  `name` varchar(20) DEFAULT NULL COMMENT '名称',
                                  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
                                  `user_name` varchar(20) DEFAULT NULL COMMENT '订单所属用户名',
                                  PRIMARY KEY (`id`),
                                  KEY `user_name_index` (`user_name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单表';



CREATE TABLE `t_order_item_2020_6` (
                                       `id` bigint(20) NOT NULL COMMENT '主键',
                                       `order_id` bigint(20) DEFAULT NULL COMMENT '订单ID',
                                       `name` varchar(20) DEFAULT NULL COMMENT '名称',
                                       `order_create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
                                       PRIMARY KEY (`id`),
                                       KEY `order_id_index` (`order_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单商品表';



CREATE TABLE `t_order_middle_test` (
  `id` BIGINT(20) NOT NULL COMMENT '主键',
  `order_id` VARCHAR(20) DEFAULT NULL COMMENT '名称',
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='订单中间表测试'

#2按照年范围分表sql
CREATE TABLE `t_order_2022` (
  `id` BIGINT(20) NOT NULL COMMENT '主键',
  `name` VARCHAR(20) DEFAULT NULL COMMENT '名称',
  `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
  `user_name` VARCHAR(20) DEFAULT NULL COMMENT '订单所属用户名',
  PRIMARY KEY (`id`),
  KEY `user_name_index` (`user_name`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='订单表'

CREATE TABLE `t_order_2023` (
  `id` BIGINT(20) NOT NULL COMMENT '主键',
  `name` VARCHAR(20) DEFAULT NULL COMMENT '名称',
  `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
  `user_name` VARCHAR(20) DEFAULT NULL COMMENT '订单所属用户名',
  PRIMARY KEY (`id`),
  KEY `user_name_index` (`user_name`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='订单表'


CREATE TABLE `t_order_item_2022` (
  `id` BIGINT(20) NOT NULL COMMENT '主键',
  `order_id` BIGINT(20) DEFAULT NULL COMMENT '订单ID',
  `name` VARCHAR(20) DEFAULT NULL COMMENT '名称',
  `order_create_time` DATETIME DEFAULT NULL COMMENT '订单创建时间',
  PRIMARY KEY (`id`),
  KEY `order_id_index` (`order_id`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='订单商品表'



CREATE TABLE `t_order_item_2023` (
  `id` BIGINT(20) NOT NULL COMMENT '主键',
  `order_id` BIGINT(20) DEFAULT NULL COMMENT '订单ID',
  `name` VARCHAR(20) DEFAULT NULL COMMENT '名称',
  `order_create_time` DATETIME DEFAULT NULL COMMENT '订单创建时间',
  PRIMARY KEY (`id`),
  KEY `order_id_index` (`order_id`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='订单商品表'

CREATE TABLE `sys_log` (
  `id` VARCHAR(32) NOT NULL,
  `log_type` INT(2) DEFAULT NULL COMMENT '日志类型(1登录日志,2操作日志)',
  `log_content` VARCHAR(1000) DEFAULT NULL COMMENT '日志内容',
  `operate_type` INT(2) DEFAULT NULL COMMENT '操作类型',
  `userid` VARCHAR(32) DEFAULT NULL COMMENT '操作用户账号',
  `username` VARCHAR(100) DEFAULT NULL COMMENT '操作用户名称',
  `ip` VARCHAR(100) DEFAULT NULL COMMENT 'IP',
  `method` VARCHAR(500) DEFAULT NULL COMMENT '请求java方法',
  `request_url` VARCHAR(255) DEFAULT NULL COMMENT '请求路径',
  `request_param` LONGTEXT DEFAULT NULL COMMENT '请求参数',
  `request_type` VARCHAR(10) DEFAULT NULL COMMENT '请求类型',
  `cost_time` BIGINT(20) DEFAULT NULL COMMENT '耗时',
  `create_by` VARCHAR(32) DEFAULT NULL COMMENT '创建人',
  `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
  `update_by` VARCHAR(32) DEFAULT NULL COMMENT '更新人',
  `update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `index_table_userid` (`userid`) USING BTREE,
  KEY `index_logt_ype` (`log_type`) USING BTREE,
  KEY `index_operate_type` (`operate_type`) USING BTREE,
  KEY `index_createtime` (`create_time`) USING BTREE
) ENGINE=MYISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='系统日志表';

CREATE TABLE `sys_log0` (
  `id` varchar(32) NOT NULL,
  `log_type` int(2) DEFAULT NULL COMMENT '日志类型(1登录日志,2操作日志)',
  `log_content` varchar(1000) DEFAULT NULL COMMENT '日志内容',
  `operate_type` int(2) DEFAULT NULL COMMENT '操作类型',
  `userid` varchar(32) DEFAULT NULL COMMENT '操作用户账号',
  `username` varchar(100) DEFAULT NULL COMMENT '操作用户名称',
  `ip` varchar(100) DEFAULT NULL COMMENT 'IP',
  `method` varchar(500) DEFAULT NULL COMMENT '请求java方法',
  `request_url` varchar(255) DEFAULT NULL COMMENT '请求路径',
  `request_param` longtext DEFAULT NULL COMMENT '请求参数',
  `request_type` varchar(10) DEFAULT NULL COMMENT '请求类型',
  `cost_time` bigint(20) DEFAULT NULL COMMENT '耗时',
  `create_by` varchar(32) DEFAULT NULL COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(32) DEFAULT NULL COMMENT '更新人',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `index_table_userid` (`userid`) USING BTREE,
  KEY `index_logt_ype` (`log_type`) USING BTREE,
  KEY `index_operate_type` (`operate_type`) USING BTREE,
  KEY `index_createtime` (`create_time`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='系统日志表';

CREATE TABLE `sys_log1` (
  `id` varchar(32) NOT NULL,
  `log_type` int(2) DEFAULT NULL COMMENT '日志类型(1登录日志,2操作日志)',
  `log_content` varchar(1000) DEFAULT NULL COMMENT '日志内容',
  `operate_type` int(2) DEFAULT NULL COMMENT '操作类型',
  `userid` varchar(32) DEFAULT NULL COMMENT '操作用户账号',
  `username` varchar(100) DEFAULT NULL COMMENT '操作用户名称',
  `ip` varchar(100) DEFAULT NULL COMMENT 'IP',
  `method` varchar(500) DEFAULT NULL COMMENT '请求java方法',
  `request_url` varchar(255) DEFAULT NULL COMMENT '请求路径',
  `request_param` longtext DEFAULT NULL COMMENT '请求参数',
  `request_type` varchar(10) DEFAULT NULL COMMENT '请求类型',
  `cost_time` bigint(20) DEFAULT NULL COMMENT '耗时',
  `create_by` varchar(32) DEFAULT NULL COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(32) DEFAULT NULL COMMENT '更新人',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `index_table_userid` (`userid`) USING BTREE,
  KEY `index_logt_ype` (`log_type`) USING BTREE,
  KEY `index_operate_type` (`operate_type`) USING BTREE,
  KEY `index_createtime` (`create_time`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='系统日志表';


CREATE TABLE `tb_cust` (
  `cust_id` BIGINT (20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `cust_name` VARCHAR (20) NOT NULL COMMENT '用户名称',
  `branch_id` CHAR(3) NOT NULL COMMENT '分公司',
  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`cust_id`)
) ENGINE = INNODB AUTO_INCREMENT = 202 DEFAULT CHARSET = utf8 COMMENT = '客户信息表';


CREATE TABLE `tb_cust_fc5` (
  `cust_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `cust_name` VARCHAR(20) NOT NULL COMMENT '用户名称',
  `branch_id` CHAR(3) NOT NULL COMMENT '分公司',
  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`cust_id`)
) ENGINE=INNODB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8 COMMENT='客户信息表';
CREATE TABLE `tb_cust_fdg` (
  `cust_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `cust_name` VARCHAR(20) NOT NULL COMMENT '用户名称',
  `branch_id` CHAR(3) NOT NULL COMMENT '分公司',
  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`cust_id`)
) ENGINE=INNODB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8 COMMENT='客户信息表';

CREATE TABLE `tb_cust_fdm` (
  `cust_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `cust_name` VARCHAR(20) NOT NULL COMMENT '用户名称',
  `branch_id` CHAR(3) NOT NULL COMMENT '分公司',
  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`cust_id`)
) ENGINE=INNODB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8 COMMENT='客户信息表';


CREATE TABLE `tb_cust_fdw` (
  `cust_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `cust_name` VARCHAR(20) NOT NULL COMMENT '用户名称',
  `branch_id` CHAR(3) NOT NULL COMMENT '分公司',
  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`cust_id`)
) ENGINE=INNODB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8 COMMENT='客户信息表';





CREATE TABLE `t_complex` (
  `order_id` BIGINT(20) NOT NULL,
  `user_id` BIGINT(20) NOT NULL,
  `address_id` BIGINT(20) NOT NULL,
  `city` VARCHAR(32) DEFAULT NULL,
  `status` TINYINT(4) DEFAULT NULL,
  `creator` VARCHAR(32) DEFAULT NULL,
  `create_time` DATETIME DEFAULT NULL,
  `updater` VARCHAR(32) DEFAULT NULL,
  `update_time` DATETIME DEFAULT NULL,
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMI;



CREATE TABLE `t_complex_0` (
  `order_id` BIGINT(20) NOT NULL,
  `user_id` BIGINT(20) NOT NULL,
  `address_id` BIGINT(20) NOT NULL,
  `city` VARCHAR(32) DEFAULT NULL,
  `status` TINYINT(4) DEFAULT NULL,
  `creator` VARCHAR(32) DEFAULT NULL,
  `create_time` DATETIME DEFAULT NULL,
  `updater` VARCHAR(32) DEFAULT NULL,
  `update_time` DATETIME DEFAULT NULL,
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

CREATE TABLE `t_complex_1` (
  `order_id` BIGINT(20) NOT NULL,
  `user_id` BIGINT(20) NOT NULL,
  `address_id` BIGINT(20) NOT NULL,
  `city` VARCHAR(32) DEFAULT NULL,
  `status` TINYINT(4) DEFAULT NULL,
  `creator` VARCHAR(32) DEFAULT NULL,
  `create_time` DATETIME DEFAULT NULL,
  `updater` VARCHAR(32) DEFAULT NULL,
  `update_time` DATETIME DEFAULT NULL,
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

CREATE TABLE `t_complex_2` (
  `order_id` BIGINT(20) NOT NULL,
  `user_id` BIGINT(20) NOT NULL,
  `address_id` BIGINT(20) NOT NULL,
  `city` VARCHAR(32) DEFAULT NULL,
  `status` TINYINT(4) DEFAULT NULL,
  `creator` VARCHAR(32) DEFAULT NULL,
  `create_time` DATETIME DEFAULT NULL,
  `updater` VARCHAR(32) DEFAULT NULL,
  `update_time` DATETIME DEFAULT NULL,
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

CREATE TABLE `t_complex_3` (
  `order_id` BIGINT(20) NOT NULL,
  `user_id` BIGINT(20) NOT NULL,
  `address_id` BIGINT(20) NOT NULL,
  `city` VARCHAR(32) DEFAULT NULL,
  `status` TINYINT(4) DEFAULT NULL,
  `creator` VARCHAR(32) DEFAULT NULL,
  `create_time` DATETIME DEFAULT NULL,
  `updater` VARCHAR(32) DEFAULT NULL,
  `update_time` DATETIME DEFAULT NULL,
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;



CREATE TABLE `tb_dict` (
  `id` BIGINT UNSIGNED NOT NULL COMMENT '主键',
  `status_code` TINYINT NOT NULL DEFAULT 1 COMMENT '状态编号',
  `status_name` VARCHAR(10) NOT NULL DEFAULT '' COMMENT '状态名称',
  `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_status_code` (`status_code`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='状态码表';

CREATE TABLE `tb_student` (
  `order_id` BIGINT(20) NOT NULL COMMENT '主键',
  `user_id` INT UNSIGNED NOT NULL DEFAULT '0' COMMENT '用户id',
  `price` INT UNSIGNED NOT NULL DEFAULT '0' COMMENT '价格(单位:分)',
  `order_status` TINYINT UNSIGNED NOT NULL DEFAULT '1' COMMENT '订单状态(1:待付款,2:已付款,3:已取消)',
  `order_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `title` VARCHAR(100)  NOT NULL DEFAULT '' COMMENT '订单标题',
  PRIMARY KEY (`order_id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_order_time` (`order_time`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

CREATE TABLE `tb_student_1` (
  `order_id` BIGINT(20) NOT NULL COMMENT '主键',
  `user_id` INT UNSIGNED NOT NULL DEFAULT '0' COMMENT '用户id',
  `price` INT UNSIGNED NOT NULL DEFAULT '0' COMMENT '价格(单位:分)',
  `order_status` TINYINT UNSIGNED NOT NULL DEFAULT '1' COMMENT '订单状态(1:待付款,2:已付款,3:已取消)',
  `order_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `title` VARCHAR(100)  NOT NULL DEFAULT '' COMMENT '订单标题',
  PRIMARY KEY (`order_id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_order_time` (`order_time`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';


CREATE TABLE `tb_student_2` (
  `order_id` BIGINT(20) NOT NULL COMMENT '主键',
  `user_id` INT UNSIGNED NOT NULL DEFAULT '0' COMMENT '用户id',
  `price` INT UNSIGNED NOT NULL DEFAULT '0' COMMENT '价格(单位:分)',
  `order_status` TINYINT UNSIGNED NOT NULL DEFAULT '1' COMMENT '订单状态(1:待付款,2:已付款,3:已取消)',
  `order_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `title` VARCHAR(100)  NOT NULL DEFAULT '' COMMENT '订单标题',
  PRIMARY KEY (`order_id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_order_time` (`order_time`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

4 application配置(需要哪个放开注释就可以)

server:
  port: 7010
spring:
  profiles:
    active: sharding
  application:
    name: jeecg-sharding
  config:
    import:
      - optional:nacos:jeecg.yaml
      - optional:nacos:[email protected]@.yaml
      #导入classpath下,按照年月范围分表
      #- classpath:sharding-y-m-range-dev.yml
      #导入classpath下,按照年范围分表
      # - classpath:sharding-y-range-dev.yml
      #导入classpath下,分库分表
      #- classpath:application-sharding-multi.yml
      #需求:业务上存在多个分支机构,需要将不同分支的客户拆分到不同的表
      #- classpath:sharding-diff-branch-dev.yml
      #复合分片算法单表
      #- classpath:sharding-complex-dev.yml
      #广播表
      -  classpath:application-sharding-broadcast.yml
  cloud:
    nacos:
      config:
        server-addr: @config.server-addr@
      discovery:
        server-addr: ${spring.cloud.nacos.config.server-addr}

案列

  案列1:按照年月范围分表

 sharding-y-m-range-dev.yml

#单库分表配置
spring:
  shardingsphere:
    props:
      sql-show: true
    datasource:
      names: ds
      #添加分库数据源
      ds:
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://jeecg-boot-mysql:3306/shardingjdbc?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
        username: root
        password: xgm@2023..
        type: com.alibaba.druid.pool.DruidDataSource

    # 规则配置
    rules:
      sharding:
        tables:
          # 逻辑表名称
          t_order:
            #配置具体表的数据节点
            actual-data-nodes: ds.t_order_$->{2023..2023}_$->{3..6}
            # 分表策略None(不分片),Inline(最基础的策略、只支持普通的查询和排序),
            #Standard(可支持范围查询,但查询条件若不是分片键或没有查询条件,则查所有表。需要定制具体的分片算法类),
            #Complex(支持范围查询,并支持多分片键的复杂分片策略)
            #Hint(操作时可以指定具体的库、表。无需分片键,只需定制具体的分片算法类)
            table-strategy:
              #分配策略:
              standard:
                # 分片算法名称
                sharding-algorithm-name: table-classbased
                # 分片列名称(对应数据库字段)
                sharding-column: create_time
          t_order_item:
              actual-data-nodes: ds.t_order_item_$->{2023..2023}_$->{3..6}
              table-strategy:
                standard:
                  sharding-column: order_create_time
                  sharding-algorithm-name: table-classbased
        # 配置绑定表,每一行为一组
        binding-tables:
          - t_order,t_order_item
        defaultDataSourceName: ds
        sharding-algorithms:
          table-classbased:
            props:
              strategy: standard
              algorithmClassName: org.jeecg.modules.sharding.algorithm.StandardYMRangeShardAlgorithm
            type: CLASS_BASED
        # 分布式序列算法配置
        key-generators:
          snowflake:
            type: SNOWFLAKE
            props:
              worker-id: 123


package org.jeecg.modules.sharding.algorithm;


import com.alibaba.fastjson.JSON;
import com.google.common.collect.Range;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import org.jeecg.modules.sharding.utils.ShardingUtils;

import java.util.*;


/**
 * @version 1.0
 * @Author zhaozhiqiang
 * @Date 2023/6/16 14:09
 * @Description //TODO 标准年月分表算法
 */
@Slf4j
public class StandardYMRangeShardAlgorithm implements StandardShardingAlgorithm {
    private Properties props = new Properties();

    public static void main(String[] args) {

        for (int i=0;i<2;i++) {
            //根据值进行取模,得到一个目标值
           int temp= i% 2;
           System.out.println(temp);

        }
        String name="test_01";
        System.out.println(name.indexOf("1"));
    }

    /**
     * 用于处理=和IN的分片
     *
     * @param availableTargetNames           目标/物理表分片的集合(表名)
     * @param preciseShardingValue 逻辑表相关信息  precise准确的
     * @return
     */
    @Override
    public String doSharding(Collection availableTargetNames, PreciseShardingValue preciseShardingValue) {
        log.info("精确集合:{},值:{}", JSON.toJSONString(availableTargetNames),JSON.toJSONString(preciseShardingValue));
        Date date = preciseShardingValue.getValue();
        String suffix = ShardingUtils.getSuffixByYearMonth(date);
        for (String tableName : availableTargetNames) {
            if (tableName.endsWith(suffix)) {
                return tableName;
            }
        }
        throw new IllegalArgumentException("未找到匹配的数据表");
    }

    /**
     * 用于处理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理
     *
     * @param availableTargetNames
     * @param rangeShardingValue
     * @return
     */
    @Override
    public Collection doSharding(Collection availableTargetNames, RangeShardingValue rangeShardingValue) {
        List list = new ArrayList<>();
        log.info("范围集合:{},值:{}", JSON.toJSONString(availableTargetNames),JSON.toJSONString(rangeShardingValue));
        Range valueRange = rangeShardingValue.getValueRange();
        Date lowerDate = valueRange.lowerEndpoint();
        Date upperDate = valueRange.upperEndpoint();
        String lowerSuffix = ShardingUtils.getSuffixByYearMonth(lowerDate);
        String upperSuffix = ShardingUtils.getSuffixByYearMonth(upperDate);
        //年月前缀计算
        TreeSet suffixList = ShardingUtils.getSuffixYMListForRange(lowerSuffix, upperSuffix);
        for (String tableName : availableTargetNames) {
            if (containTableName(suffixList, tableName)) {
                list.add(tableName);
            }
        }
        log.info("match tableNames-----------------------" + list.toString());
        return list;
    }
    private boolean containTableName(Set suffixList, String tableName) {
        boolean flag = false;
        for (String s : suffixList) {
            if (tableName.endsWith(s)) {
                flag = true;
                break;
            }
        }
        return flag;
    }
    /**
     * 初始化对象的时候调用的方法
     */
    @Override
    public void init() {
    }

    /**
     * 对应分片算法(sharding-algorithms)的类型
     *
     * @return
     */
    @Override
    public String getType() {
        return "STANDARD_MOD";
    }

    @Override
    public Properties getProps() {
        return this.props;
    }

    /**
     * 获取分片相关属性
     *
     * @param properties
     */
    @Override
    public void setProps(Properties properties) {
        this.props = properties;
    }
}
package org.jeecg.modules.sharding.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.sharding.entity.Order;
import org.jeecg.modules.sharding.service.IOrderItemService;
import org.jeecg.modules.sharding.service.IOrderService;
import org.jeecg.modules.sharding.utils.DateUtils;
import org.jeecg.modules.sharding.vo.OrderAndItemVo;
import org.springframework.web.bind.annotation.*;

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

@Api(tags = "按照年范围分表")
@RestController
@RequestMapping("/sharding/y")
@Slf4j
public class ShardingYRangeController {
    @Resource
    private IOrderService orderService;

    @Resource
    private IOrderItemService orderItemService;
    /**
     * 制造测试数据
     *
     * @return
     */
    @ApiOperation(value = "制造测试数据", httpMethod = "POST")
    @PostMapping("/initData")
    public Result initData() {
        orderService.initData();
        return Result.OK();
    }
    @ApiOperation(value = "根据时间段查询列表数据", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "bgtm", value = "开始时间", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "edtm", value = "结束时间", required = false, dataType = "String", paramType = "query")
    })
    @GetMapping("/listAllByDate")
    public Result listAll(@RequestParam(value = "bgtm", required = false) String bgtm, @RequestParam(value = "edtm", required = false) String edtm) {
        LambdaQueryWrapper objectLambdaQueryWrapper = new LambdaQueryWrapper();
        if(StringUtils.isNotBlank(bgtm)&&StringUtils.isNotBlank(edtm)){
            objectLambdaQueryWrapper.between(Order::getCreateTime, DateUtils.parseDate(bgtm), DateUtils.getEndTimeOfDay(edtm));
            objectLambdaQueryWrapper.orderByDesc(Order::getCreateTime);
        }
        List list = orderService.list(objectLambdaQueryWrapper);
        return Result.OK(list);
    }
}
package org.jeecg.modules.sharding.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.sharding.entity.Order;
import org.jeecg.modules.sharding.vo.OrderAndItemVo;

import java.util.Date;
import java.util.List;

/**
 * 

* Mapper 接口 *

* * @author XHD * @since 2020-07-16 */ public interface OrderMapper extends BaseMapper { List listByRowNum(@Param("suffix") String suffix, @Param("size") Integer size, @Param("rowNum") Integer rowNum , @Param("userName") String userName); List getItemByParentId(@Param("id")Long id, @Param("name")String name, @Param("createTime")String createTime); List getUnBindLis(@Param("id")Long id,@Param("createTime")String createTime); List unitMainAndShardingList(@Param("id")Long id,@Param("createTime")String createTime); }




     

    

    

    

package org.jeecg.modules.sharding.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.modules.sharding.entity.Order;
import org.jeecg.modules.sharding.entity.OrderItem;
import org.jeecg.modules.sharding.mapper.OrderMapper;
import org.jeecg.modules.sharding.service.IOrderItemService;
import org.jeecg.modules.sharding.service.IOrderService;
import org.jeecg.modules.sharding.utils.DataUtils;
import org.jeecg.modules.sharding.utils.DateUtils;
import org.jeecg.modules.sharding.utils.ShardingUtils;
import org.jeecg.modules.sharding.vo.OrderAndItemVo;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 

* 服务实现类 *

* * @author XHD * @since 2020-07-16 */ @Service @DS("sharding") public class OrderServicImpl extends ServiceImpl implements IOrderService { @Resource private IOrderItemService orderItemService; @Override public void initData() { //主表50万 从表50*2=100万 int count = 5000; //每次入库20条 int size = 1000; List tempList = new ArrayList<>(); List orderItemList = new ArrayList<>(); while (count > 0) { addBatch(count, size, tempList, orderItemList); count -= size; try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public Page listPage(String bgtm, String edtm, Integer current, Integer size, String userName) { Page pageParam = new Page<>(); pageParam.setCurrent(current); if (null != size) { pageParam.setSize(size); } LambdaQueryWrapper ew = new LambdaQueryWrapper<>(); ew.between(Order::getCreateTime, DateUtils.parseDate(bgtm), DateUtils.getEndTimeOfDay(edtm)); ew.orderByDesc(Order::getCreateTime); if (StringUtils.isNotBlank(userName)) { ew.eq(Order::getUserName, userName); } Page page =this.page(pageParam,ew); LambdaQueryWrapper orderItemWrapper = new LambdaQueryWrapper() .between(OrderItem::getOrderCreateTime, DateUtils.parseDate(bgtm), DateUtils.getEndTimeOfDay(edtm)); this.appendOrderItem(page.getRecords(), orderItemWrapper); return page; } @Override public List listPageByTime(String lastCreateTime, Integer lastRowNum, Integer size, String userName) { //lastCreateTime 有助于快速定位当前查询的分表 ,如果是第一页则可不传,默认使用当前时间 Date date = StringUtils.isBlank(lastCreateTime) ? new Date() : DateUtils.parseTime(lastCreateTime); String suffix = ShardingUtils.getSuffixByYearMonth(date); int resultSize = size == null ? 10 : size; //rowNum用于获取当前页数据的起始位置,如果是第一页可以不传,默认为0 int rowNum = lastRowNum == null ? 0 : lastRowNum; List orderList = baseMapper.listByRowNum(suffix, resultSize, rowNum, userName); if (orderList.size() > 0) { while (orderList.size() < resultSize) { //查询出的数据不足 找更早的分表补足 if ("2020_6".equals(suffix)) { //假设最早的分表为 t_order_2020_6 break; } suffix = ShardingUtils.getPrevSuffix(suffix); List tempOrderList = baseMapper.listByRowNum(suffix, resultSize - orderList.size(), 0, userName); if (tempOrderList.size() > 0) { orderList.addAll(tempOrderList); } } //获取orderList中数据的时间范围 查询子表数据 LambdaQueryWrapper orderItemWrapper = new LambdaQueryWrapper() .between(OrderItem::getOrderCreateTime, orderList.get(orderList.size() - 1).getCreateTime(), orderList.get(0).getCreateTime()); this.appendOrderItem(orderList, orderItemWrapper); } return orderList; } @Override public Order findById(Long id, String createTime) { LambdaQueryWrapper ew = new LambdaQueryWrapper<>(); ew.eq(Order::getCreateTime,DateUtils.parseTime(createTime)); ew.eq(Order::getId,id); Order one = this.getOne(ew); return one; } @Override public void removeById(Long id, String createTime) { Order entity=new Order(); entity.setId(id); entity.setCreateTime(DateUtils.parseTime(createTime)); this.removeById(entity); } @Override public List getItemByParentId(Long id, String name, String createTime) { return baseMapper.getItemByParentId(id,name,createTime); } @Override public List getUnBindLis(Long id,String createTime) { return baseMapper.getUnBindLis(id,createTime); } @Override public List unitMainAndShardingList(Long id, String createTime) { return baseMapper.unitMainAndShardingList(id,createTime); } private void appendOrderItem(List orderList, LambdaQueryWrapper ew) { if (null != orderList && orderList.size() > 0) { Set orderIds = orderList.stream().map(Order::getId).collect(Collectors.toSet()); ew.in(OrderItem::getOrderId, orderIds).orderByDesc(OrderItem::getOrderCreateTime); List orderItemList = orderItemService.list(ew); Map> orderItemMap = DataUtils.listToMapForLong("orderId", orderItemList); orderList.forEach(order -> order.setOrderItemList(orderItemMap.get(order.getId()))); } } private void addBatch(int ct, int size, List tempList, List orderItemList) { for (int i = 0; i < size; i++) { long orderId = IdWorker.getId(); // Date orderCreateTime = randomCreateTime(new Random()); Date orderCreateTime = new Date(); tempList.add(new Order().setId(orderId).setName("订单-" + (ct - i)).setCreateTime(orderCreateTime) .setUserName("guest-" + new Random().nextInt(1000))); orderItemList.add(new OrderItem().setOrderId(orderId).setName("商品-" + (ct * 2 - i * 2)).setOrderCreateTime(orderCreateTime)); orderItemList.add(new OrderItem().setOrderId(orderId).setName("商品-" + (ct * 2 - i * 2 - 1)).setOrderCreateTime(orderCreateTime)); } saveBatch(tempList); orderItemService.saveBatch(orderItemList); tempList.clear(); orderItemList.clear(); } // private Date randomCreateTime(Random random) { // Calendar calendar = Calendar.getInstance(); // calendar.set(Calendar.YEAR, 2023); // calendar.set(Calendar.MONTH, 5); // calendar.set(Calendar.DAY_OF_MONTH, random.nextInt(31) + 1); // calendar.set(Calendar.HOUR_OF_DAY, random.nextInt(24)); // calendar.set(Calendar.MINUTE, random.nextInt(60)); // calendar.set(Calendar.SECOND, random.nextInt(60)); // return calendar.getTime(); // } }

后续代码太多就不一一贴出来,下载地址

https://download.csdn.net/download/weixin_38501485/87917171

你可能感兴趣的:(java,sharding,分库分表,复合分片,范围分片)