从结算业务 深入理解 并发,mysql 乐观锁,可重复读

从结算业务 深入理解 并发,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);

写好程序 不简单,并发场景下 会出很多问题,处理的好,得加深 知识的理解。

你可能感兴趣的:(从结算业务 深入理解 并发,mysql 乐观锁,可重复读)