虚拟电商-数据库分库分表(二)
本文章介绍:使用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-serviceprofiles:active: devcloud:consul:host: 127.0.0.1port: 8500discovery:serviceName: ${spring.application.name}config:enabled: trueformat: yaml prefix: configdefaultContext: 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.129password: chongbaport: 6379sleuth:sampler:probability: 1 #这是收集比例,1表示100% ,全部收集zipkin:#base-url: http://localhost:9411sender:type: rabbitrabbitmq:host: 192.168.200.129port: 5672username: guestpassword: guest shardingsphere:datasource:ds0:driver-class-name: com.mysql.cj.jdbc.Driverpassword: 123456type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.200.129:3306/chongba_schedule0?serverTimezone=Asia/Shanghaiusername: rootds1:driver-class-name: com.mysql.cj.jdbc.Driverpassword: 123456type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.200.129:3306/chongba_schedule1?serverTimezone=Asia/Shanghaiusername: rootnames: 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 数据源@Autowiredprivate DataSource dataSource;@Beanpublic 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.129password: chongbaport: 6379zipkin:#base-url: http://localhost:9411sender:type: rabbitrabbitmq:host: 192.168.200.129port: 5672username: guestpassword: guest shardingsphere:datasource:ds0:driver-class-name: com.mysql.cj.jdbc.Driverpassword: 123456type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.200.129:3306/chongba_schedule0?serverTimezone=Asia/Shanghaiusername: rootds1:driver-class-name: com.mysql.cj.jdbc.Driverpassword: 123456type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.200.129:3306/chongba_schedule1?serverTimezone=Asia/Shanghaiusername: rootnames: ds0,ds1sharding:tables:taskinfo:actual-data-nodes: ds$->{0..1}.taskinfo_$->{0..1}key-generator: #主键生成策略column: task_idtype: SNOWFLAKEdatabase-strategy: #分库策略inline:sharding-column: task_typealgorithm-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.129password: chongbaport: 6379zipkin:#base-url: http://localhost:9411sender:type: rabbitrabbitmq:host: 192.168.200.129port: 5672username: guestpassword: guest shardingsphere:datasource:ds0:driver-class-name: com.mysql.cj.jdbc.Driverpassword: 123456type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.200.129:3306/chongba_schedule0?serverTimezone=Asia/Shanghaiusername: rootds1:driver-class-name: com.mysql.cj.jdbc.Driverpassword: 123456type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.200.129:3306/chongba_schedule1?serverTimezone=Asia/Shanghaiusername: rootnames: ds0,ds1sharding:tables:taskinfo:actual-data-nodes: ds$->{0..1}.taskinfo_$->{0..1}key-generator: #主键生成策略column: task_idtype: SNOWFLAKEdatabase-strategy: #分库策略inline:sharding-column: task_typealgorithm-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_typealgorithm-expression: ds$->{task_type % 2}key-generator:column: task_idtype: SNOWFLAKEtable-strategy: #分表策略inline:sharding-column: priorityalgorithm-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并做出修改
@Beanpublic 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.129password: chongbaport: 6379zipkin:#base-url: http://localhost:9411sender:type: rabbitrabbitmq:host: 192.168.200.129port: 5672username: guestpassword: guest shardingsphere:datasource:ds0:driver-class-name: com.mysql.cj.jdbc.Driverpassword: 123456type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.200.129:3306/chongba_schedule0?serverTimezone=Asia/Shanghaiusername: rootds1:driver-class-name: com.mysql.cj.jdbc.Driverpassword: 123456type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.200.129:3306/chongba_schedule1?serverTimezone=Asia/Shanghaiusername: rootnames: ds0,ds1sharding:tables:taskinfo:actual-data-nodes: ds$->{0..1}.taskinfo_$->{0..1}key-generator: #主键生成策略column: task_idtype: SNOWFLAKEdatabase-strategy: #分库策略inline:sharding-column: task_typealgorithm-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_idtype: SNOWFLAKEdatabase-strategy: #分库策略inline:sharding-column: task_typealgorithm-expression: ds$->{task_type % 2}table-strategy: #分表策略 按月分库standard:precise-algorithm-class-name: com.chongba.schedule.conf.ShardingAlgorithmMonthsharding-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 数据路由到的表名称*/@Overridepublic 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.Driverpassword: 123456type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.200.129:3306/chongba_schedule?serverTimezone=Asia/Shanghaiusername: rootds0:driver-class-name: com.mysql.cj.jdbc.Driverpassword: 123456type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://192.168.200.129:3306/chongba_schedule0?serverTimezone=Asia/Shanghaiusername: rootnames: df,ds0sharding:tables:ok: actual-data-nodes: df.okkey-generator: #主键生成策略column: idtype: 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);
相关文章:
虚拟电商-数据库分库分表(二)
本文章介绍:使用Sharding-JDBC实现数据库分库分表,数据库分片策略,实现数据库按月分表 一、Sharding-JDBC使用 1.1.准备环境 步骤一:分库分表sql脚本导入 创建了两个数据库:chongba_schedule0 和chongba_schedule1…...
进程间通信--匿名管道
进程间通信介绍 进程间通信目的 数据传输:一个进程需要将它的数据发送给另一个进程资源共享:多个进程之间共享同样的资源。通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件&…...
人工智能治理的两会声音:技术规范与伦理风险探讨
摘要 在最近的两会期间,科技界代表聚焦人工智能(AI)治理问题,提出多项建议。这些建议涵盖AI技术规范、伦理风险预防与控制等方面。代表们强调建立健全法律法规和技术标准体系,确保AI健康发展。同时,重视公众…...
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的图书商城 网上书城、图书销售系统、图书销售平台 |Java|SSM|HTML|JSP| 项目采用技术: ①:开发环境:IDEA、JDK1.8、Maven、Tomcat ②:技术栈:Java、…...
Powershell如何查询 windows defender是否开启
可以通过PowerShell使用以下方法检查Windows Defender(Microsoft Defender Antivirus)的状态: 方法1:使用 Get-MpComputerStatus 命令 此命令会返回Microsoft Defender的全面状态,包括实时保护、病毒定义版本等&#…...
【漫话机器学习系列】133.决定系数(R²:Coefficient of Determination)
决定系数()详解 决定系数()是回归分析中用于评估模型拟合优度的一个重要统计指标。它表示自变量(特征变量)能够解释因变量(目标变量)变异的程度,取值范围为 [0,1] 或 (−…...
【MySQL】数据库简要介绍和简单应用
目录 数据库简要介绍 SQL 的简单应用 需要注意的: 数据库简要介绍 数据库(database)是指长期存储在计算机内,有组织的、可共享的数据集合。它可视为一个电子化的文件柜,用来存储电子文件,用户可以对文件中的数据进行査询、新增、更新、删…...
【Kubernets】Deployment 和 StatefulSet 有什么区别?什么时候用 StatefulSet?
Deployment 和 StatefulSet 的区别 在 Kubernetes 中,Deployment 和 StatefulSet 都用于管理 Pod,但它们适用于不同的场景。 1. Deployment:管理无状态应用 特点: 无状态:Pod 之间相互独立,不需要保持顺…...
Machine Learning: 十大基本机器学习算法
机器学习算法分类:监督学习、无监督学习、强化学习 基本的机器学习算法: 线性回归、支持向量机(SVM)、最近邻居(KNN)、逻辑回归、决策树、k平均、随机森林、朴素贝叶斯、降维、梯度增强。 机器学习算法大致可以分为三类: 监督学习算法 (Sup…...
洛谷 P2801 教主的魔法 题解
之前学过 莫队 算法,其运用了分块思想;但是我居然是第一次写纯种的分块题目。 题意 给你一个长度为 n n n 的序列 a a a(一开始 ∀ a i ∈ [ 1 , 1000 ] \forall a_i\in[1,1000] ∀ai∈[1,1000])。要求执行 q q q 次操作&…...
【八股文】ArrayList和LinkedList的区别
先讲讲两者是如何实现的 ArrayList public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {transient Object[] elementData; private int size; } 通过源码可以看出,ArrayLis…...
函数的引用/函数的默认参数/函数的占位参数/函数重载
函数的引用 #include<iostream> using namespace std;//引用的本质在c内部实现,是一个指针常量//交换函数 //1.值传递 void mySwap01(int a, int b) {int temp a;a b;b temp; }//2.地址传递 void mySwap02(int *a, int *b) {int temp *a;*a *b;*b temp…...
《鸿蒙系统下AI模型训练加速:时间成本的深度剖析与优化策略》
在当今数字化浪潮中,鸿蒙系统凭借其独特的分布式架构与强大的生态潜力,为人工智能的发展注入了新的活力。随着AI应用在鸿蒙系统上的日益普及,如何有效降低模型训练的时间成本,成为了开发者与研究者们亟待攻克的关键课题。这不仅关…...
.npy文件介绍
.npy 文件是 NumPy 库专用的二进制文件格式,用于高效存储和加载 NumPy 数组(即矩阵或多维数组)。这种格式保留了数组的维度、数据类型(dtype)、形状(shape)等元信息,加载时无需手动解…...
汇编语言 | 王爽 | 学习笔记
汇编语言 | 王爽 | 学习笔记 文章目录 汇编语言 | 王爽 | 学习笔记一、基础知识1、指令2、存储器3、总线1、总线2、CPU对存储器的读写3、CPU对外设的控制 4、内存地址空间 二、寄存器1、寄存器2、通用寄存器3、8086CPU给出物理地址的方法4、段寄存器1、CS和IP2、DS 和 [address…...
JumpServer基础功能介绍演示
堡垒机可以让运维人员通过统一的平台对设备进行维护,集中的进行权限的管理,同时也会对每个操作进行记录,方便后期的溯源和审查,JumpServer是由飞致云推出的开源堡垒机,通过简单的安装配置即可投入使用,本文…...
java字符串案例 //要求:将输入的字符串中的数字转换为罗马数字,长度小于9(运用方法:查表法)
package test13; import test11.S;import java.util.Scanner; public class Num {public static void main(String[] args){ // I II III IV V VI VII VIII IX//要求:将输入的字符串中的数字转换为罗马数字,长度小于9(运用方法:查表法&#x…...
EDID读取学习
简介 Video BIOS可以被认为是一个具有独立硬件抽象层的操作系统。它不会阻止或监视操作系统、应用程序或设备驱动程序对硬件的直接访问。虽然不推荐,但一些DOS应用程序确实可以改变基本的硬件设置,而根本不需要通过视频BIOS。大多数现代应用程序和操作系统都避免直接使用硬件…...
【笔记】深度学习模型训练的 GPU 内存优化之旅:综述篇
开设此专题,目的一是梳理文献,目的二是分享知识。因为笔者读研期间的研究方向是单卡上的显存优化,所以最初思考的专题名称是“显存突围:深度学习模型训练的 GPU 内存优化之旅”,英文缩写是 “MLSys_GPU_Memory_Opt”。…...
车载以太网测试-13【网络层-IGMP协议】
目录 1 摘要2 IGMP协议概述2.1 IGMP 在 TCP/IP 协议栈中的位置2.2 IGMP 与以太网的关系2.3 为什么需要IGMP协议?2.4 IGMP报文结构2.4.1 IGMPv1 报文结构2.4.2 IGMPv2 报文结构2.4.3 IGMPv3 报文结构 3 IGMP通信原理3.1 GMP 的通信流程3.2 IGMP协议完整流程示例 4 总…...
2024山东大学计算机复试上机真题
2024山东大学计算机复试上机真题 2024山东大学计算机复试机试真题 历年山东大学计算机复试上机真题 历年山东大学计算机复试机试真题 在线评测:传动门:pgcode.cn 最长递减子序列 题目描述 输入数字 n,和 n 个整数,输出该数字…...
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 递归调用性…...
深入理解 Xtensa 架构 ESP32 内存架构(SRAM、IRAM、IROM、DRAM、DROM详解)
在 ESP32 及其他 Xtensa 架构 MCU 中,内存被划分为不同的区域,以优化性能和存储管理。这些内存区域包括 SRAM, IRAM, DRAM, IROM, DROM,它们各有用途。 1. 内存区域总览 ESP32 的内存架构主要由: SRAM(Static RAM&am…...
每日一题——63. 不同路径 II
题目链接:63. 不同路径 II - 力扣(LeetCode) 代码: class Solution { public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int m obstacleGrid.size();int n obstacleGrid[0].size();…...
如何配置 Docker 以实现无需 sudo 使用
1. 背景知识:为什么需要 sudo? Docker 是一个容器化平台,其核心组件包括: Docker 守护进程(dockerd):负责管理容器的创建、运行和销毁。Docker CLI:用户通过命令行工具(…...
[文献阅读] 可变形卷积DCN - Deformable Convolutional Networks
**文献信息:**Deformable Convolutional Networks arxiv.org/abs/1703.06211 发表于ICCV 2017,提出了可变形卷积DCN(Deformable ConvNets) 摘要 卷积神经网络(CNN)由于其构建模块固定的几何结构天然地局限…...
【统计学相关笔记】2. 多元正态的Cochran定理
fisher 引理 如何说明一个线性变换和二次型独立: 二次型矩阵和线性变换阵乘积0即可。...
蓝桥杯刷题——第十五届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组
一、0握手问题 - 蓝桥云课 算法代码: #include <iostream> using namespace std; int main() {int sum0;for(int i49;i>7;i--)sumi;cout<<sum<<endl;return 0; } 直接暴力,题意很清晰,累加即可。 二、0小球反弹 - 蓝…...
Canoe Panel常用控件
文章目录 一、Panel 中控件分类1. 指示类控件2. 功能类控件3. 信号值交互类控件4. 其他类控件 二、控件使用方法1. Group Box 控件2. Input/Output Box控件3. Static Text控件4. Button控件5. Switch/Indicator 控件 提示:Button 和 Switch 的区别参考 一、Panel 中…...
