可针对自己业务进行技术选型,我们常使用的技术为 xxl-job,针对于我们上文中所说到的不同的跑批任务设置的时间不合理,我们即可利用 xxljob 的子任务特性进行嵌套的任务处理,在保费代扣任务完成后紧接着进行本息代扣任务
防止OOM,切记分片处理这一点其实没有什么好展开的,在对跑批任务进行开发的时候,一定要记住分片处理
一次性加载所有数据到内存里,无疑是自掘坟墓
那么,如何优雅分片呢?
这时候小张同学举手了:分片我会呀,比如像这种扣款的都是以时间维度来的,我直接 select * from t_repay_plan where repay_time <= "2022-04-10" limit 0,1000
那么,现在我们找个数据来看下这种深度分片的性能如何
我在数据库中插入了大概两百万条数据,把制造数据的过程也分享给你们
// 1、创建表CREATE TABLE `t_repay_plan` (`id` int(11) NOT NULL AUTO_INCREMENT,`repay_time` datetime DEFAULT NULL COMMENT '还款时间',`str1` int(11) DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=3099998 DEFAULT CHARSET=utf8mb4// 2、创建存储过程 delimiter $$create procedure insert_repayPlan()begindeclare n int default 1;while n< 3000000do insert into t_repay_plan(repay_time,str1) values(concat( CONCAT(FLOOR(2015 + (RAND() * 1)),'-',LPAD(FLOOR(10 + (RAND() * 2)),2,0),'-',LPAD(FLOOR(1 + (RAND() * 25)),2,0))),n);set n = n+1;end while;end// 3、执行存储过程call insert_repayPlan();

文章插图
随着逐渐的数据偏移,数据耗时逐渐增加 。因为这种深度分页是将数据全部查询出来,并且抛弃掉,效果自然不是那么尽如人意
其实我们分片还有一种方法,那就是利用到我们的 id 来进行分页处理(当然是你的 id 是需要保证业务增长,并且结合具体的业务场景来进行分析)
我们同样来试一下怎么利用 id ,进行分片的耗时情况

文章插图
我们可以看到效果很明显,利用 id 进行分片,效果是优于我们的这个还款时间字段的
当然关于跑批过程中 「覆盖索引的使用、尽量不去 select * 等、批量进行插入」 等 sql 常见点不和大家一一展开说明了
针对所需数据进行 map 的构造我们再写一个简单的反例
// 调用数据库查询需跑批数据List<BizApplyDo> bizApplyDoList = this.listGetBizApply(businessDate);// for 循环处理数据for(BizApplyDo ba : bizApplyDoList) {// 查询账户数据BizAccountDo bizAccountDo = this.getBizAccount(ba.getbizApplyId());// 账户处理逻辑.. 省略// 查询扣款人数据CustDo custDo = this.getCust(ba.getUserId);// 扣款人处理逻辑.. 省略}我们可以这样进行改造(伪代码、忽略判空处理)// 调用数据库查询需跑批数据List<BizApplyDo> bizApplyDoList = this.listGetBizApply(businessDate);// 构建业务申请编号集合List<String> bizApplyIdList= bizApplyDoList.parallelStream().map(BizApplyDo::getbizApplyId()).collect(Collectors.toList());// 批量进行账户查询List<BizAccountDo> bizAccountDoList = this.listGetBizAccount(bizApplyIdList);// 构建账户 MapMap<String, BizAccountDo> accountMap = bizAccountDoList.parallelStream().collect(Collectors.toMap(BizAccountDo::getBizApplyId(), Function.identity()))// 扣款人数据同样处理for(BizApplyDo ba : bizApplyDoList) {account = accountMap.get(ba.getbizApplyId()) // 账户处理逻辑.. 省略}尽可能减少 for 循环的嵌套,减少数据库频繁连接和销毁事务控制长点心一旦我们使用了@Trancation进行管理事务,那么就要求组内开发人员在开发过程中需要瞪大眼睛去注意事务的控制范围
因为 @Trancation 是在第一个 sql 方法执行的时候就开启了事务,在方法未结束之前都不会进行提交,有些同学接手改造这个方法的时候,没有注意到这个方法是被@Trancation覆盖,那么在这个方法里加入一些RPC的远程调用、消息发送、文件写入、缓存更新等操作
1、这些操作自身是无法回滚的,这就会导致数据的不一致 。可能RPC调用成功了,但是本地事务回滚了,可是PRC调用无法回滚了 。
2、在事务中有远程调用,就会拉长整个事务 。那么久会导致本事务的数据库连接一直被占用,那么如果类似操作过多,就会导致数据库连接池耗尽或者单个链接超时
我曾经就见过一个方法,经过多人之手后,从而因为大事务导致数据库连接被强行销毁的悲剧
所以「我们可以有选择性的去使用编程性事务去处理」我们的业务逻辑,让接手的同学可以明确看到什么时候开启了事务,什么时候提交了事务,也尽可能将我们的事务粒度的范围缩小
推荐阅读
- 幼儿园教师疫情工作总结?疫情幼儿教师年度总结
- 东方红红茶,红茶制茶大师俞
- 奶少找催乳师有用吗_
- 自考幼师证怎么考?
- 盖碗红茶茶艺表演视频,绿茶茶艺师表演
- 家长对老师最想说的一句话是什么?家长对老师想说的话及要求
- 感受祁门红茶,池州祁门红茶
- 幼儿园教师面试的自我介绍和技巧介绍
- 师德师风心得体会短篇?师德师风心得体会2022年幼儿园
- 和田玉籽料|舊藏和田玉籽料“枣红皮 太师少狮”.
