虚拟电商-数据库分库分表(二)

news2025/3/16 19:58:07

本文章介绍:使用Sharding-JDBC实现数据库分库分表,数据库分片策略,实现数据库按月分表

一、Sharding-JDBC使用

1.1.准备环境

步骤一:分库分表sql脚本导入

创建了两个数据库:chongba_schedule0 和chongba_schedule1

每个数据库中任务表和任务日志表各自两张:taskinfo_0,taskinfo_1,taskinfo_logs_0,taskinfo_logs_1

DROP database if exists `chongba_schedule0`;
CREATE DATABASE `chongba_schedule0` DEFAULT CHARACTER SET utf8;
USE `chongba_schedule0`;
CREATE TABLE `taskinfo_0` (
  `task_id` bigint(20) NOT NULL    comment '任务id',
  `execute_time` datetime(3) NOT NULL comment '执行时间',
  `parameters` longblob  comment '参数',
  `priority` int(11) NOT NULL      comment '优先级',
  `task_type` int(11) NOT NULL     comment '任务类型',
  PRIMARY KEY (`task_id`),
  KEY `index_taskinfo_time` (`task_type`,`priority`,`execute_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `taskinfo_1` (
  `task_id` bigint(20) NOT NULL    comment '任务id',
  `execute_time` datetime(3) NOT NULL comment '执行时间',
  `parameters` longblob  comment '参数',
  `priority` int(11) NOT NULL      comment '优先级',
  `task_type` int(11) NOT NULL     comment '任务类型',
  PRIMARY KEY (`task_id`),
  KEY `index_taskinfo_time` (`task_type`,`priority`,`execute_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `taskinfo_logs_0` (
  `task_id` bigint(20) NOT NULL     comment '任务id',
  `execute_time` datetime(3) NOT NULL  comment '执行时间',
  `parameters` longblob   comment '参数',
  `priority` int(11) NOT NULL       comment '优先级',
  `task_type` int(11) NOT NULL      comment '任务类型',
  `version` int(11) NOT NULL        comment '版本号,用乐观锁',
  `status` int(11) DEFAULT '0' COMMENT '状态 0=初始化状态 1=EXECUTED 2=CANCELLED',
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `taskinfo_logs_1` (
  `task_id` bigint(20) NOT NULL     comment '任务id',
  `execute_time` datetime(3) NOT NULL  comment '执行时间',
  `parameters` longblob   comment '参数',
  `priority` int(11) NOT NULL       comment '优先级',
  `task_type` int(11) NOT NULL      comment '任务类型',
  `version` int(11) NOT NULL        comment '版本号,用乐观锁',
  `status` int(11) DEFAULT '0'      comment '状态 0=初始化状态 1=EXECUTED 2=CANCELLED',
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;drop database if exists `chongba_schedule1`;
CREATE DATABASE `chongba_schedule1` DEFAULT CHARACTER SET utf8;
USE `chongba_schedule1`;
CREATE TABLE `taskinfo_0` (
  `task_id` bigint(20) NOT NULL    comment '任务id',
  `execute_time` datetime(3) NOT NULL comment '执行时间',
  `parameters` longblob  comment '参数',
  `priority` int(11) NOT NULL      comment '优先级',
  `task_type` int(11) NOT NULL     comment '任务类型',
  PRIMARY KEY (`task_id`),
  KEY `index_taskinfo_time` (`task_type`,`priority`,`execute_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `taskinfo_1` (
  `task_id` bigint(20) NOT NULL    comment '任务id',
  `execute_time` datetime(3) NOT NULL comment '执行时间',
  `parameters` longblob  comment '参数',
  `priority` int(11) NOT NULL      comment '优先级',
  `task_type` int(11) NOT NULL     comment '任务类型',
  PRIMARY KEY (`task_id`),
  KEY `index_taskinfo_time` (`task_type`,`priority`,`execute_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `taskinfo_logs_0` (
  `task_id` bigint(20) NOT NULL     comment '任务id',
  `execute_time` datetime(3) NOT NULL  comment '执行时间',
  `parameters` longblob   comment '参数',
  `priority` int(11) NOT NULL       comment '优先级',
  `task_type` int(11) NOT NULL      comment '任务类型',
  `version` int(11) NOT NULL        comment '版本号,用乐观锁',
  `status` int(11) DEFAULT '0'      comment '状态 0=初始化状态 1=EXECUTED 2=CANCELLED',
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `taskinfo_logs_1` (
  `task_id` bigint(20) NOT NULL     comment '任务id',
  `execute_time` datetime(3) NOT NULL  comment '执行时间',
  `parameters` longblob   comment '参数',
  `priority` int(11) NOT NULL       comment '优先级',
  `task_type` int(11) NOT NULL      comment '任务类型',
  `version` int(11) NOT NULL        comment '版本号,用乐观锁',
  `status` int(11) DEFAULT '0'      comment '状态 0=初始化状态 1=EXECUTED 2=CANCELLED',
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

步骤二:在chongba_schedule_service 模块的pom文件中引入依赖:

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.0.0-RC1</version>
</dependency>
<dependency>
    <!-- druid数据源-->
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.19</version>
</dependency>

1.2.基本概念

逻辑表

是对于水平拆分的数据库(表)的同一类表的总称。例如:订单数据根据主键尾数拆分为10张表,分别是t_order_0到t_order_9,他们的逻辑表可以表示为t_order,在应用程序中操作的是逻辑表。

@TableName("taskinfo")
public class TaskInfoEntity implements Serializable {
    .........
}

真实表

在分片的数据库中真实存在的物理表。即上个示例中的t_order_0到t_order_9。

数据节点

数据分片的最小单元, 由数据源名称和数据表组成

例如:db_0.t_order_0。 表示 数据库db_0下名称为t_order_0的表

1.3.数据源整合

下面我们进行数据源整合

分库分表之后,就不用之前的数据源了,改用新的数据源,因为有多个数据库,所以需要配置多数据源。

对于程序中的代码我们无需修改,只需要通过配置支持多数据源即可,官方文档中有提供好的配置参考。

为了让配置更加的清晰和有条理,我们使用新的配置,操作步骤如下:

步骤一:在chongba_schedule_service模块中的bootstrap.yml配置文件中修改加载的配置:schedule-sharding

spring:
   application:  
    name: schedule-service
   profiles:
    active: dev
   cloud:
    consul:
      host: 127.0.0.1
      port: 8500
      discovery:
        serviceName: ${spring.application.name}
      config:
        enabled: true
        format: yaml         
        prefix: config
        defaultContext: schedule-sharding   # 只修改此处,其他和之前一样
        data-key: data

步骤二:在Consul中建立新的key/value配置,Consul中的key为:config/schedule-sharding,dev/data,注意在Consul中新建key/value时要在最外层

然后在该key下配置对应的value如下:(可以先在applicatoin-dev.yml文件中配置好再配置到Consul)

chongba: 
  preLoad: 1 #自定义预加载时间
  selectMasterZookeeper: 192.168.200.129:2181  
spring:
  redis:
    host: 192.168.200.129
    password: chongba
    port: 6379
  sleuth:
    sampler:
      probability: 1     #这是收集比例,1表示100% ,全部收集
  zipkin:
    #base-url: http://localhost:9411
    sender:
      type: rabbit
  rabbitmq:
    host: 192.168.200.129
    port: 5672
    username: guest
    password: guest    
  shardingsphere:
        datasource:
            ds0:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: 123456
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://192.168.200.129:3306/chongba_schedule0?serverTimezone=Asia/Shanghai
                username: root
            ds1:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: 123456
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://192.168.200.129:3306/chongba_schedule1?serverTimezone=Asia/Shanghai
                username: root
            names: ds0,ds1

步骤三:在chongba_schedule_service模块中启动:ScheduleApplication,查看控制台输出

3.1)项目基于SpringBoot,启动时会自动配置,其中有一个关于数据源的自动配置类如下:

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@EnableConfigurationProperties({DataSourceProperties.class})
@Import({DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class})
public class DataSourceAutoConfiguration {
    ......
}

@ConfigurationProperties(
    prefix = "spring.datasource"
)
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
    private Class<? extends DataSource> type;
    private String driverClassName;
    private String url;
    private String username;
    private String password;
}

默认去加载spring的数据源,而我们使用sharding-jdbc后用的不再是spring默认提供的数据源,通过配置可以发现我们使用的是:spring.shardingsphere.datasource

解决方案:

在启动类:ScheduleApplication 上将系统默认spring的数据源自动配置类排除

//@SpringBootApplication
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@MapperScan("com.chongba.schedule.mapper")
@ComponentScan({"com.chongba.cache","com.chongba.schedule"})
@EnableScheduling
@EnableAsync
public class ScheduleApplication {
    ..........
}

3.2)sqlSessionFactory属于mybatis的工厂类,该工厂类没有创建好

原因:默认情况下spring整合mybtis会自动创建sqlSessionFactory,而创建sqlSessionFactory需要用到数据源dataSource,采用的也是spring默认提供的数据源,通过我们上面的分析,此时的数据源是由shardingsphere来提供的,因此创建sqlSessionFactory不成功!

解决方案:

在chongba_schedule_service模块中的com.chongba.schedule.conf包下创建

MybatisPlusShardingConfiguration 配置类,将shardingDataSource数据源集成到mybatis-plus中去

/**
 *mybatis-plus 使用sharding-jdbc数据源问题
 */
@Configuration
@AutoConfigureAfter(DataSource.class)
public class MybatisPlusShardingConfiguration {
      
    //获取sharding 数据源
    @Autowired
    private DataSource dataSource;
    
    @Bean
    public MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean(){
        MybatisSqlSessionFactoryBean mysqlplus = new MybatisSqlSessionFactoryBean();
        mysqlplus.setDataSource(dataSource);
        return mysqlplus;
    }
}

3.3)现在虽然数据源的问题解决了,但是数据库表的问题还没解决,因为报错信息是数据库chongba_schedule1中的taskinfo表不存在,我们现在的表是taskinfo_0,taskinfo_1,如何解决?

二、分片路由配置

2.1.taskinfo表分片路由配置

配置好了数据源,对于数据库表并没有做任何处理,我们要对数据库表进行分片路由配置,当向数据库表中写入数据的时候通过特定的路由规则来判定数据写入到哪个库及哪个表中

例如对taskinfo 表根据用户task_type字段分库,priority字段分表,修改Consul中config/schedule-sharding,dev/data下的value如下

chongba: 
  preLoad: 1 #自定义预加载时间
  selectMasterZookeeper: 192.168.200.129:2181  
spring:
  redis:
    host: 192.168.200.129
    password: chongba
    port: 6379
  zipkin:
    #base-url: http://localhost:9411
    sender:
      type: rabbit
  rabbitmq:
    host: 192.168.200.129
    port: 5672
    username: guest
    password: guest      
  shardingsphere:
        datasource:
            ds0:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: 123456
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://192.168.200.129:3306/chongba_schedule0?serverTimezone=Asia/Shanghai
                username: root
            ds1:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: 123456
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://192.168.200.129:3306/chongba_schedule1?serverTimezone=Asia/Shanghai
                username: root
            names: ds0,ds1
        sharding:
              tables:
                taskinfo:
                  actual-data-nodes: ds$->{0..1}.taskinfo_$->{0..1}
                  key-generator: #主键生成策略
                    column: task_id
                    type: SNOWFLAKE
                  database-strategy:  #分库策略
                    inline:
                      sharding-column: task_type
                      algorithm-expression: ds$->{task_type % 2}
                  table-strategy: #分表策略
                    inline:
                      sharding-column: priority 
                      algorithm-expression: taskinfo_$->{priority % 2}

注意:
数据节点含义 采用 e x p r e s s i o n 或 {expression}或 expression->{expression}
也是 s p r i n g b o o t 读取变量的规则,为了防止冲突,建议 {}也是springboot 读取变量的规则,为了防止冲突,建议 也是springboot读取变量的规则,为了防止冲突,建议->

db0
├── taskinfo_0
└── taskinfo_1

db1
├── taskinfo_1
└── taskinfo_1

以上对于数据源和数据表的配置都是连续,下面看不连续的配置,比如要配置成:
db0
├── t_order0
└── t_order1
db1
├── t_order2
├── t_order3
└── t_order4
这种情况对于actual-data-nodes的配置:
actual-data-nodes: db0.t_order − > 0..1 , d b 1. t o r d e r ->{0..1},db1.t_order >0..1,db1.torder->{2…4}

2.2.taskinfo表分片测试

测试:

在chongba_schedule_service工程中找到测试类:TaskInfoMapperTest,运行测试方法:test1(),

TaskInfoEntity taskInfoEntity = new TaskInfoEntity();
taskInfoEntity.setExecuteTime(new Date());
taskInfoEntity.setPriority(1);
taskInfoEntity.setTaskType(1001);
taskInfoEntity.setParameters("test".getBytes());
taskInfoMapper.insert(taskInfoEntity);

测试案例1:按照分片路由规则:task_type % 2 == 1该数据将被分配到ds1数据源上,priority % 2 ==1,该数据将被分配到taskinfo_1表中存储。

**测试案例2:**可以更改TaskType =1000 priority =10,继续测试

2.3.taskinfo_logs表分片路由配置

taskinfo_logs分片策略跟taskinfo表一致,所以直接修改Consul中config/schedule-sharding,dev/data下的value如下:

chongba: 
  preLoad: 1 #自定义预加载时间
  selectMasterZookeeper: 192.168.200.129:2181  
spring:
  redis:
    host: 192.168.200.129
    password: chongba
    port: 6379
  zipkin:
    #base-url: http://localhost:9411
    sender:
      type: rabbit
  rabbitmq:
    host: 192.168.200.129
    port: 5672
    username: guest
    password: guest      
  shardingsphere:
        datasource:
            ds0:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: 123456
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://192.168.200.129:3306/chongba_schedule0?serverTimezone=Asia/Shanghai
                username: root
            ds1:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: 123456
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://192.168.200.129:3306/chongba_schedule1?serverTimezone=Asia/Shanghai
                username: root
            names: ds0,ds1
        sharding:
              tables:
                taskinfo:
                  actual-data-nodes: ds$->{0..1}.taskinfo_$->{0..1}
                  key-generator: #主键生成策略
                    column: task_id
                    type: SNOWFLAKE
                  database-strategy:  #分库策略
                    inline:
                      sharding-column: task_type
                      algorithm-expression: ds$->{task_type % 2}
                  table-strategy: #分表策略
                    inline:
                      sharding-column: priority 
                      algorithm-expression: taskinfo_$->{priority % 2}
                taskinfo_logs:
                  actual-data-nodes: ds$->{0..1}.taskinfo_logs_$->{0..1}
                  database-strategy: #分库策略
                    inline:
                      sharding-column: task_type
                      algorithm-expression: ds$->{task_type % 2}
                  key-generator:
                    column: task_id
                    type: SNOWFLAKE
                  table-strategy: #分表策略
                    inline:
                      sharding-column: priority
                      algorithm-expression: taskinfo_logs_$->{priority % 2}

2.4.taskinfo_logs表分片测试:

在chongba_schedule_service工程中,找到测试类:TaskInfoLogsMapperTest,运行测试方法:test()

测试案例1:task_type=1003,priority=3,数据会被路由到:ds1.taskinfo_logs_1中

结果:

1:数据能够正常入库

2:乐观锁出现问题

对应乐观锁我们希望:

但是实际情况:

乐观锁出现问题的原因:

1:关于乐观锁我们之前是在启动类ScheduleApplication中进行了如下配置,将乐观锁插件放入IOC容器中然后自动的注册到SqlSessionFactory

@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
    return new OptimisticLockerInterceptor();
}

但是现在我们使用的是mybatis-plus集成了sharding-jdbc数据源后的MybatisSqlSessionFactoryBean,我们的乐观锁插件并没有自动的注册进去。

在chongba_schedule_service模块中的com.chongba.schedule.conf包下找到配置类:

MybatisPlusShardingConfiguration并做出修改

 @Bean
    public MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean(){
        MybatisSqlSessionFactoryBean mysqlplus = new MybatisSqlSessionFactoryBean();
        mysqlplus.setDataSource(dataSource);
        mysqlplus.setPlugins(new Interceptor[]{new OptimisticLockerInterceptor()}); //注册插件
        return mysqlplus;
    }

注意:注释掉启动类中关于乐观锁插件的配置!
最后再次进行测试!

三、Sharding-JDBC分片策略

3.1.分片策略介绍
Sharding分片策略继承自ShardingStrategy,提供了5种分片策略:

在这里插入图片描述

1.StandardShardingStrategy
标准分片策略。提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。

StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。

1:PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。

2:RangeShardingAlgorithm是可选的,用于处理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。

1566457504884
2.ComplexShardingStrategy

复合分片策略。提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。

ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此Sharding-JDBC并未做过多的封装,而是直接将分片键值组合以及分片操作符交于算法接口,完全由应用开发者实现,提供最大的灵活度。

3.InlineShardingStrategy
Inline表达式分片策略。使用Groovy的Inline表达式,提供对SQL语句中的=和IN的分片操作支持。

InlineShardingStrategy只支持单分片键,对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_${user_id % 8} 表示t_user表按照user_id按8取模分成8个表,表名称为t_user_0到t_user_7。

1566457463389

4.HintShardingStrategy
通过Hint而非SQL解析的方式分片的策略。

对于分片字段非SQL决定,而由其他外置条件决定的场景,可使用SQL Hint灵活的注入分片字段。例:内部系统,按照员工登录主键分库,而数据库中并无此字段。SQL Hint支持通过Java API和SQL注释(待实现)两种方式使用。

5.NoneShardingStrategy

不分片的策略。

6.自定义分片策略介绍

由于分片算法和业务实现紧密相关,因此Sharding-JDBC是通过分片策略将各种场景提炼出来,提供更高层级的抽象,并提供接口让应用开发者自行实现分片算法。

为了方便获取定义的参数及集成,自定义的算法要实现Sharding-jdbc 提供的接口,

Sharding提供了以下4种算法接口:

1):精确分片算法–PreciseShardingAlgorithm

用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。

2):范围分片算法–RangeShardingAlgorithm

用于处理使用单一键作为分片键的BETWEEN AND进行分片的场景。需要配合StandardShardingStrategy使用。

3):复合分片算法–ComplexKeysShardingAlgorithm

用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。

注 : 我们在业务开发中,经常有根据用户id 查询某用户的记录列表,又有根据某个业务主键查询该用户的某记录的需求,这就需要用到复合分片算法。比如,订单表中,我们既需要查询某个userId的某时间段内的订单列表数据,又需要根据orderId查询某条订单数据。这里,orderId与userId就属于复合分片键。

4):Hint分片算法–HintShardingAlgorithm

Hint分片指的是对于分片字段非SQL决定,而由其他外置条件决定的场景,可以通过使用SQL Hint灵活注入分片字段。

Hint分片策略是绕过SQL解析的,因此能够通过实现该算法来实现Sharding-JDBC不支持的语法限制。

用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用。

四、任务日志表按月分表

需求:

对于数据库表taskinfo,我们消费完任务或者取消完任务后数据都会从该表中去删除,而对于taskinfo_logs日志表数据是一直累加的,对于数据量大的情况下只分两张表仍然会存在性能瓶颈,我们现在要对taskinfo_logs根据任务的执行时间execute_time进行按月分表

实现:

步骤1:导入数据表

步骤2:在Consul中创建新的配置并使用

2.1:在chonba_sechedule_service的bootstrap.yml配置文件中修改加载的配置:schedule-sharding-month

2.2:在Consul中添加新的key:config/schedule-sharding-month,dev/data ,并配置如下值:

chongba: 
  preLoad: 1 #自定义预加载时间
  selectMasterZookeeper: 192.168.200.129:2181  
spring:
  redis:
    host: 192.168.200.129
    password: chongba
    port: 6379
  zipkin:
    #base-url: http://localhost:9411
    sender:
      type: rabbit
  rabbitmq:
    host: 192.168.200.129
    port: 5672
    username: guest
    password: guest      
  shardingsphere:
        datasource:
            ds0:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: 123456
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://192.168.200.129:3306/chongba_schedule0?serverTimezone=Asia/Shanghai
                username: root
            ds1:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: 123456
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://192.168.200.129:3306/chongba_schedule1?serverTimezone=Asia/Shanghai
                username: root
            names: ds0,ds1
        sharding:
              tables:
                taskinfo:
                  actual-data-nodes: ds$->{0..1}.taskinfo_$->{0..1}
                  key-generator: #主键生成策略
                    column: task_id
                    type: SNOWFLAKE
                  database-strategy:  #分库策略
                    inline:
                      sharding-column: task_type
                      algorithm-expression: ds$->{task_type % 2}
                  table-strategy: #分表策略
                    inline:
                      sharding-column: priority 
                      algorithm-expression: taskinfo_$->{priority % 2}
                taskinfo_logs: #逻辑表
                  actual-data-nodes: ds$->{0..1}.taskinfo_logs_20$->{19..22}_$->{1..12}
                  key-generator: #主键生成策略
                    column: task_id
                    type: SNOWFLAKE
                  database-strategy:  #分库策略
                    inline:
                      sharding-column: task_type
                      algorithm-expression: ds$->{task_type % 2}
                  table-strategy: #分表策略 按月分库
                    standard:
                      precise-algorithm-class-name: com.chongba.schedule.conf.ShardingAlgorithmMonth
                      sharding-column: execute_time

步骤3:自定义分片算法实现

在chongba_schedule_service工程中的包com.chongba.schedule.conf下创建分片算法类:

ShardingAlgorithmMonth,实现PreciseShardingAlgorithm接口,实现根据任务的执行时间进行按月分片。

@Slf4j
public class ShardingAlgorithmMonth implements PreciseShardingAlgorithm<Date> {/**
     * 执行分片策略   
     * @param collection                    候选表集合 
     * @param preciseShardingValue          精确分片值:任务的执行时间
     * @return                              数据路由到的表名称
     */
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<Date> preciseShardingValue) {
        String node = null;
        try {
            DateFormat dateFormat = new SimpleDateFormat("yyyy_M");
            String dateStr = dateFormat.format(preciseShardingValue.getValue());
            for (String nodeCandidate : collection) {
                if(nodeCandidate.endsWith(dateStr)){
                    node  = nodeCandidate;
                    break;
                }
            }
        } catch (Exception e) {
            log.error("sharding-sphere doSharding exception {}",e.getMessage());
        }
        return node;
    }   
}

步骤4:找到测试类:TaskInfoLogsMapperTest,运行测试方法:test(),查看控制台输出

报错信息:无法将数据路由到表

解决方案:debug运行测试方法,查看问题,发现是由于时间格式的问题,修改分片算法实现,然后再次测试!

五、分库分表优化介绍

5.1.优化1

优化1:任务表和任务日志表我们做了分库分表,对于有一些表,数据量很小,我们无需进行分库分表,有哪些解决方案?

广播表:指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。

不指定分库分表策略:如果某张表不需要分库分表,那我们可以不指定分库分表策略,让这张表的数据直接落到指定的数据源中即可

spring:
  shardingsphere:
        datasource:
            df:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: 123456
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://192.168.200.129:3306/chongba_schedule?serverTimezone=Asia/Shanghai
                username: root
            ds0:
                driver-class-name: com.mysql.cj.jdbc.Driver
                password: 123456
                type: com.alibaba.druid.pool.DruidDataSource
                url: jdbc:mysql://192.168.200.129:3306/chongba_schedule0?serverTimezone=Asia/Shanghai
                username: root
            names: df,ds0
        sharding:
              tables:
                ok: 
                  actual-data-nodes: df.ok
                  key-generator: #主键生成策略
                    column: id
                    type: SNOWFLAKE

5.2.优化2

优化2:在延迟任务系统中我们有一个启动后进行数据恢复,然后定时的预加载数据库中的数据到缓存,我们查询数据的时候是按照任务类型和优先级进行的分组查询,

QueryWrapper qryWrapper = new QueryWrapper();
qryWrapper.select("task_type", "priority");
qryWrapper.groupBy("task_type","priority");
List<Map<String, Object>>  result = taskMapper.selectMaps(qryWrapper);

问题:分库分表后要根据任务类型和优先级进行分组查询,势必要检索所有数据源和所有表才能得到分组的结果,我们如何处理?

业务改造:对于任务的类型和优先级可以在后台做成可配置的,建立一张表任务配置表taskConfig,存储所有的任务类型和优先级分组关系,添加任务的时候,类型和优先级不得随意指定,必须是配置表中已配置好的,这样子,在做数据恢复的时候我们就无需从所有数据源中去分组检索,而只需要从配置表中查询数据即可

reloadData优化:

//改造成读取字典表
List<TaskConfig> configList= taskConfigMapper.selectAll();// QueryWrapper qryWrapper = new QueryWrapper();
// qryWrapper.select("task_type", "priority");
// qryWrapper.groupBy("task_type","priority");
// List<Map<String, Object>>  result = taskMapper.selectMaps(qryWrapper);
log.info("分组 {}",configList);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2316232.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

进程间通信--匿名管道

进程间通信介绍 进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程资源共享&#xff1a;多个进程之间共享同样的资源。通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;它们&#xff09;发生了某种事件&…

C#opencv 遍历图像中所有点 不在圆范围内的点变为黑色,在圆范围内的保持原色

C#opencv 遍历图像中所有点 不在圆范围内的点变为黑色,在圆范围内的保持原色 安装 Install-Package OpenCvSharp4 Install-Package OpenCvSharp4.Windows 普通实现 using System; using System.Collections.Generic; using System.Linq; using OpenCvSharp; // 添加OpenCV引用…

基于SSM + JSP 的图书商城系统

基于SSM的图书商城 网上书城、图书销售系统、图书销售平台 &#xff5c;Java&#xff5c;SSM&#xff5c;HTML&#xff5c;JSP&#xff5c; 项目采用技术&#xff1a; ①&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Tomcat ②&#xff1a;技术栈&#xff1a;Java、…

【漫话机器学习系列】133.决定系数(R²:Coefficient of Determination)

决定系数&#xff08;&#xff09;详解 决定系数&#xff08;&#xff09;是回归分析中用于评估模型拟合优度的一个重要统计指标。它表示自变量&#xff08;特征变量&#xff09;能够解释因变量&#xff08;目标变量&#xff09;变异的程度&#xff0c;取值范围为 [0,1] 或 (−…

Machine Learning: 十大基本机器学习算法

机器学习算法分类&#xff1a;监督学习、无监督学习、强化学习 基本的机器学习算法&#xff1a; 线性回归、支持向量机(SVM)、最近邻居(KNN)、逻辑回归、决策树、k平均、随机森林、朴素贝叶斯、降维、梯度增强。 机器学习算法大致可以分为三类&#xff1a; 监督学习算法 (Sup…

【八股文】ArrayList和LinkedList的区别

先讲讲两者是如何实现的 ArrayList public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {transient Object[] elementData; private int size; } 通过源码可以看出&#xff0c;ArrayLis…

汇编语言 | 王爽 | 学习笔记

汇编语言 | 王爽 | 学习笔记 文章目录 汇编语言 | 王爽 | 学习笔记一、基础知识1、指令2、存储器3、总线1、总线2、CPU对存储器的读写3、CPU对外设的控制 4、内存地址空间 二、寄存器1、寄存器2、通用寄存器3、8086CPU给出物理地址的方法4、段寄存器1、CS和IP2、DS 和 [address…

JumpServer基础功能介绍演示

堡垒机可以让运维人员通过统一的平台对设备进行维护&#xff0c;集中的进行权限的管理&#xff0c;同时也会对每个操作进行记录&#xff0c;方便后期的溯源和审查&#xff0c;JumpServer是由飞致云推出的开源堡垒机&#xff0c;通过简单的安装配置即可投入使用&#xff0c;本文…

EDID读取学习

简介 Video BIOS可以被认为是一个具有独立硬件抽象层的操作系统。它不会阻止或监视操作系统、应用程序或设备驱动程序对硬件的直接访问。虽然不推荐,但一些DOS应用程序确实可以改变基本的硬件设置,而根本不需要通过视频BIOS。大多数现代应用程序和操作系统都避免直接使用硬件…

【笔记】深度学习模型训练的 GPU 内存优化之旅:综述篇

开设此专题&#xff0c;目的一是梳理文献&#xff0c;目的二是分享知识。因为笔者读研期间的研究方向是单卡上的显存优化&#xff0c;所以最初思考的专题名称是“显存突围&#xff1a;深度学习模型训练的 GPU 内存优化之旅”&#xff0c;英文缩写是 “MLSys_GPU_Memory_Opt”。…

2024山东大学计算机复试上机真题

2024山东大学计算机复试上机真题 2024山东大学计算机复试机试真题 历年山东大学计算机复试上机真题 历年山东大学计算机复试机试真题 在线评测&#xff1a;传动门&#xff1a;pgcode.cn 最长递减子序列 题目描述 输入数字 n&#xff0c;和 n 个整数&#xff0c;输出该数字…

Vue 计算属性与 Data 属性同名问题深度解析

文章目录 1. 问题背景与核心概念1.1 Vue 响应式系统架构1.2 核心概念定义 2. 同名问题的技术分析2.1 同名场景示例2.2 问题发生机制 3. 底层原理剖析3.1 Vue 初始化流程3.2 响应式系统关键代码 4. 问题解决方案4.1 最佳实践建议4.2 错误处理机制 5. 性能影响分析5.1 递归调用性…

[文献阅读] 可变形卷积DCN - Deformable Convolutional Networks

**文献信息&#xff1a;**Deformable Convolutional Networks arxiv.org/abs/1703.06211 发表于ICCV 2017&#xff0c;提出了可变形卷积DCN&#xff08;Deformable ConvNets&#xff09; 摘要 卷积神经网络&#xff08;CNN&#xff09;由于其构建模块固定的几何结构天然地局限…

【统计学相关笔记】2. 多元正态的Cochran定理

fisher 引理 如何说明一个线性变换和二次型独立&#xff1a; 二次型矩阵和线性变换阵乘积0即可。

蓝桥杯刷题——第十五届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组

一、0握手问题 - 蓝桥云课 算法代码&#xff1a; #include <iostream> using namespace std; int main() {int sum0;for(int i49;i>7;i--)sumi;cout<<sum<<endl;return 0; } 直接暴力&#xff0c;题意很清晰&#xff0c;累加即可。 二、0小球反弹 - 蓝…

Canoe Panel常用控件

文章目录 一、Panel 中控件分类1. 指示类控件2. 功能类控件3. 信号值交互类控件4. 其他类控件 二、控件使用方法1. Group Box 控件2. Input/Output Box控件3. Static Text控件4. Button控件5. Switch/Indicator 控件 提示&#xff1a;Button 和 Switch 的区别参考 一、Panel 中…

【软考-架构】11.3、设计模式-新

✨资料&文章更新✨ GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目录 项目中的应用设计模式创建型设计模式结构型设计模式行为型设计模式 &#x1f4af;考试真题题外话 项目中的应用 在实际项目中&#xff0c;我应用过多种设计模式来解决不同…

【大模型(LLMs)RAG 检索增强生成 面经】

1 RAG 基础面 1.1 为什么大模型需要外挂 (向量) 知识库? 如何将外部知识注入大模型,最直接的方法:利用外部知识对大模型进行微调。 思路: 构建几十万量级的数据,然后利用这些数据 对大模型进行微调,以将 额外知识注入大模型 优点: 简单粗暴 缺点: 这几十万量级的数据…

Centos 7 安装达梦数据库

一、环境准备 1. 确认操作系统的版本和数据库的版本是否一致 cat /etc/redhat-release 2. 关闭防火墙 查看防火墙状态 firewall-cmd --state 停止firewall systemctl stop firewalld.service 禁止firewall开机启动 systemctl disable firewalld.service 3. 修改文件l…

@Autowired 注解在构造器上的使用规则(字段注入也挺好的)

背景 在看Spring Framework官方文档时&#xff0c;看到这样一段描述&#xff1a; As of Spring Framework 4.3, an Autowired​ annotation on such a constructor is no longer necessary if the target bean defines only one constructor to begin with. However, if seve…