从结算业务 深入理解 并发,mysql 乐观锁,可重复读
结算 一般就是 ,把一些未结算的订单 金额,周期性的 结算 到 对应的账户 表里面去。
一般就是 通过定时任务 分批跑,比如每个月 几号 结算一次 给供应商。
思路一:
根据条件
while(true){
// 查询一批数据处理
// 满足条件 break
// 处理业务 更改账户 ,记录流水,更改一批状态
}
思路一 存在的问题:
可能会死锁:
模拟:更改账户 一般都会使用乐观锁 ,改成功 就记录 流水 更改一批数据的状态。
假如刚好 并发操作账户 (就会有一批数据没有处理),那么由于 mysql 5.6 以后隔离级别是可重复 读,所以就会 一直查询到那批数据未处理,而账户表又是 乐观锁 ,由于可重复读 导致版本号 一直读的不是最新的。所以就卡在这里了,很好模拟出来。
思路二
for(i=1;i<=totalPage,i++){
// 一页页处理
//处理业务 更改账户 ,记录流水,更改一批状态
}
思路二存在问题
分页处理完成后 ,乐观锁操作账户 会出现一批数据未处理 。
分页只能当前页只能是第一页,不能是 i ,因为处理完成后 状态变化,分页数据就不对了 会跳过一些数据。
思路三
相对比较完美 解决 并发场景,且能保证所有数据全部处理一边,不会漏掉数据。
for(i=1;i<=totalPage,i++){
// 一页页处理
// 固定 当前页 为 1
//处理业务 更改账户 ,记录流水,更改一批状态 ,记录有没有发生并发操作。
}
// 循环完成后,判断是否发生了并发,因为并发 就会存在 数据未处理
// 存在并发 就在使用 可调度线程池 在调度 一下结算 逻辑
private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
scheduledExecutorService.schedule(()->{
log.info("重跑任务");
},20,TimeUnit.SECONDS);
写好程序 不简单,并发场景下 会出很多问题,处理的好,得加深 知识的理解。
网友评论