织梦教育网站开发,工商网站,网站建设收费报价表,wordpress图片位置大家好#xff0c;我是烤鸭#xff1a;
今天分享的是spring 多线程 事务的实际应用场景#xff1a;
上一篇讲了大概的原理,主要是针对事务的开始和执行过程(数据库链接#xff0c;隔离级别#xff0c;threadlocal线程绑定)。https://blog.csdn.net/Angry_Mills/article/…大家好我是烤鸭
今天分享的是spring 多线程 事务的实际应用场景
上一篇讲了大概的原理,主要是针对事务的开始和执行过程(数据库链接隔离级别threadlocal线程绑定)。https://blog.csdn.net/Angry_Mills/article/details/82502288 下面从实际的角度分析一下。
以下场景的演示代码地址:
https://gitee.com/fireduck_admin/demo-mutithread.git
1. 模拟场景 1.1 方法未加 Transactional 注解,new Thread 方式的主子线程 事务提交情况 主线程和子线程事务分别提交(主线程提交后子线程提交) 1.2 方法加 Transactional 注解,new Thread 方式的主子线程 事务提交情况 主线程和子线程事务一起提交 下面只考虑加注解方式的情况 1.3 主线程正常,子线程异常 无论在new Thread 方式的子线程的run方法加不加 Transactional 注解子线程都是以无事务方式运行 1.4 采用springboot的 Async 注解,主线程加事务注解子线程不加事务注解 主线程和子线程事务一起提交 1.5 采用springboot的 Async 注解,主线程加事务注解子线程不加事务注解子线程异常 主线程和子线程事务都未提交 1.6 采用springboot的 Async 注解,主线程加事务注解子线程加事务注解 Transactional(propagation Propagation.REQUIRES_NEW) 主线程和子线程事务分别提交(子线程提交后主线程提交) 1.7 采用springboot的 Async 注解,主线程加事务注解子线程加事务注解 Transactional(propagation Propagation.REQUIRES_NEW),子线程异常 主线程和子线程事务都未提交 1.8 采用springboot的 Async 注解,主线程加事务注解子线程加事务注解 Transactional(propagation Propagation.REQUIRES_NEW),主线程异常 主线程未提交和子线程事务提交 总结一下。 采用 异步注解的时候配置Propagation.REQUIRES_NEW主线程和子线程确实是两个不同的事务分别提交。 但是对于子线程的异常却两个都回滚了。子线程由于异常回滚这个是没问题的。同时将异常抛给主线程主线程也跟着回滚了。 我们可以认为多线程的事务是嵌套的任何子线程的异常都会导致整个事务的事务回滚。 但是子线程如果执行完没有异常事务会直接提交不管主线程是否异常。
2. 实际场景 之前遇到的场景是这样的用户和我们发起支付是同步接口这个时候还要请求第三方的支付接口(如支付宝的接口),这时候就有个问题了。 由于支付的异步回调如此之快导致用订单号去数据库查找不到数据(数据还没提交入库)。 同一个service 做这个肯定不行就想着把入库的操作放到异步方法里做主要保证调用第三方接口前数据库已经入库了(子线程事务提交)。 这时候就可以采用 上面 1.7 的做法子线程比主线程优先提交但是即便这样也没法保证子线程的执行一定比回调快。
3. 改进 一般第三方的回调接口都有超时时间响应他不希望你做任何的逻辑处理。只要接收到消息返回 success 即可。 所以将消息的接受和业务逻辑处理分开接受到回调后返回成功同时异步处理业务逻辑。 如果这个时候还没入库把回调的唯一标识(订单号和回调参数)放到缓存。 在子线程入库后也做类似的操作查询缓存中的订单号是否存在(存在说明回调先到了),再获取回调参数手动调用一次异步通知。 当然这种还是有可能出现极端情况就是 回调方法刚查询完放缓存/子线程刚入库获取缓存同时进行。导致缓存中还是存在订单号。 这种极低概率的问题可以间隔一段时间跑补偿程序(1h 一次)。