SpringBoot多线程,保证各个子线程和主线程事物一致性

SpringBoot多线程,保证各个子线程和主线程事物一致性

  • 1、第一种写法
    • 1.1、TransactionalUntil工具类
    • 1.2、service业务类
  • 2、第二种写法
    • 2.1、service业务类

1、第一种写法

1.1、TransactionalUntil工具类

import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;import javax.annotation.Resource;@Component
public class TransactionalUntil {@Resourceprivate DataSourceTransactionManager dataSourceTransactionManager;/*** 开启事务*/public TransactionStatus begin() {TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());return transaction;}/*** 提交事务*/public void commit(TransactionStatus transactionStatus) {dataSourceTransactionManager.commit(transactionStatus);}/*** 回滚事务*/public void rollback(TransactionStatus transactionStatus) {dataSourceTransactionManager.rollback(transactionStatus);}}

1.2、service业务类

其实主要就是用CountDownLatch类的特性,和手动提交事物,来保证主线程和子线程事物的一致性。

    @Resourceprivate TransactionalUntil transactionalUntil;private volatile Boolean is_ok = new Boolean(true);@Transactional@Overridepublic void trs1() throws Exception{// 监控子线程数据CountDownLatch childMonitor = new CountDownLatch(2);// 主线程收集子线程运行最终结果List<Boolean> childResponse = new CopyOnWriteArrayList<>();//子线程在该对象上等待主线程的通知CountDownLatch mainMonitor = new CountDownLatch(1);//业务代码查询,可以换成自己的业务场景ResVmCustom resVmCustom1 = resVmCustomMapper.selectById(1);resVmCustom1.setCpu(3);resVmCustomMapper.updateById(resVmCustom1);CompletableFuture.runAsync(() -> {TransactionStatus transactionStatus = transactionalUntil.begin();try {ResVmCustom resVmCustom2 = resVmCustomMapper.selectById(2);resVmCustom2.setCpu(3);//Db.saveOrUpdate(resVmCustom2);resVmCustomMapper.updateById(resVmCustom2);childResponse.add(Boolean.TRUE);childMonitor.countDown();mainMonitor.await();if (is_ok) {// 事务提交log.info("线程  {} 正常执行,线程事务提交", Thread.currentThread().getName());transactionalUntil.commit(transactionStatus);} else {// 事务回滚log.info("线程   {} 执行出现异常,线程事务回滚", Thread.currentThread().getName());transactionalUntil.rollback(transactionStatus);}} catch (Exception e) {// 提交失败log.info("线程   {} 执行出现异常", Thread.currentThread().getName());childMonitor.countDown();childResponse.add(Boolean.FALSE);transactionalUntil.rollback(transactionStatus);}});CompletableFuture.runAsync(() -> {TransactionStatus transactionStatus = transactionalUntil.begin();try {ResVmCustom resVmCustom3 = resVmCustomMapper.selectById(3);resVmCustom3.setCpu(3);resVmCustomMapper.updateById(resVmCustom3);childResponse.add(Boolean.TRUE);childMonitor.countDown();mainMonitor.await();if (is_ok) {// 事务提交log.info("线程  {} 正常执行,线程事务提交", Thread.currentThread().getName());transactionalUntil.commit(transactionStatus);} else {// 事务回滚log.info("线程   {} 执行出现异常,线程事务回滚", Thread.currentThread().getName());transactionalUntil.rollback(transactionStatus);}} catch (Exception e) {// 提交失败log.info("线程   {} 执行出现异常", Thread.currentThread().getName());childMonitor.countDown();childResponse.add(Boolean.FALSE);transactionalUntil.rollback(transactionStatus);}});childMonitor.await();for (Boolean res : childResponse) {while (!res) {// 如果有一个子线程只想失败,改变mainResult状态 事务回滚log.info("有线程执行失败,修改标识位,事务回滚");is_ok = false;break;}}//主线程获取结果,子线程根据主线程的结果 提交或回滚mainMonitor.countDown();/*** 下面这句话,保证了主线程和子线程一致* 如果不想主线程和子线程事物保持一致,注释下面这句话就行*/if (!is_ok) {throw new RuntimeException();}}

2、第二种写法

2.1、service业务类

TransactionalUntil 工具类还用和上面的一样就行…

    /*** SpringBoot默认的自己的线程池*/@Resourceprivate ThreadPoolTaskExecutor executor;@Transactional@Overridepublic void trs2() throws Exception {// 假设三个线程要执行// 监控子线程数据CountDownLatch childMonitor = new CountDownLatch(3);// 主线程收集子线程运行最终结果List<Boolean> childResponse = new CopyOnWriteArrayList<>();//子线程在该对象上等待主线程的通知CountDownLatch mainMonitor = new CountDownLatch(1);for (int i = 1; i <= 3; i++) {int finalI = i;executor.execute(() -> {TransactionStatus transactionStatus = transactionalUntil.begin();try {//数据库增删改操作//此时只是用线程的个数i,当成业务的主键id,你自己重新声明其他变量来替代主键业务ID也行ResVmCustom resVmCustom = resVmCustomMapper.selectById(finalI);resVmCustom.setCpu(3);resVmCustomMapper.updateById(resVmCustom);childResponse.add(Boolean.TRUE);childMonitor.countDown();mainMonitor.await();if (is_ok) {// 事务提交log.info("线程  {} 正常执行,线程事务提交", Thread.currentThread().getName());transactionalUntil.commit(transactionStatus);} else {// 事务回滚log.info("线程   {} 执行出现异常,线程事务回滚", Thread.currentThread().getName());transactionalUntil.rollback(transactionStatus);}} catch (Exception e) {// 提交失败log.info("线程   {} 执行出现异常", Thread.currentThread().getName());childMonitor.countDown();childResponse.add(Boolean.FALSE);transactionalUntil.rollback(transactionStatus);}});}childMonitor.await();for (Boolean res : childResponse) {while (!res) {// 如果有一个子线程只想失败,改变mainResult状态 事务回滚log.info("有线程执行失败,修改标识位,事务回滚");is_ok = false;break;}}is_ok = false;//主线程获取结果,子线程根据主线程的结果 提交或回滚mainMonitor.countDown();/*** 下面这句话,保证了主线程和子线程一致* 如果不想主线程和子线程事物保持一致,注释下面这句话就行*/if (!is_ok) {throw new RuntimeException();}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/900985.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高并发的业务场景下,如何防止数据库事务死锁

一、 一致的锁定顺序 定义: 死锁的常见原因之一是不同的事务以不同的顺序获取锁。当多个事务获取了不同资源的锁,并且这些资源之间发生了互相依赖,就会形成死锁。 解决方法: 确保所有的事务在获取多个锁时,按照相同的顺序请求锁。例如,如果事务A需要锁定表A和表B,事务…

【从0到1学MybatisPlus】MybatisPlus入门

Mybatis-Plus 使用场景 大家在日常开发中应该能发现&#xff0c;单表的CRUD功能代码重复度很高&#xff0c;也没有什么难度。而这部分代码量往往比较大&#xff0c;开发起来比较费时。 因此&#xff0c;目前企业中都会使用一些组件来简化或省略单表的CRUD开发工作。目前在国…

力扣HOT100之链表: 148. 排序链表

这道题直接用蠢办法来做的&#xff0c;直接先遍历一遍链表&#xff0c;用一个哈希表统计每个值出现的次数&#xff0c;由于std::map<int, int>会根据键进行升序排序&#xff0c;因此我们将节点的值作为键&#xff0c;其在整个链表中的出现次数作为值&#xff0c;当所有元…

Transformer多卡训练初始化分布式环境:(backend=‘nccl‘)

Transformer多卡训练初始化分布式环境:(backend=‘nccl’) dist.init_process_group(backend=nccl)在多卡环境下初始化分布式训练环境,并为每个进程分配对应的 GPU 设备。下面为你逐行解释代码的含义: 1. 初始化分布式进程组 try:dist.init_process_group(backend=nccl) e…

使用Mybatis时在XML中SQL高亮显示的方法

如图所示&#xff0c;上方的SQL代码很像是一个字符串&#xff0c;那么如何把上方的SQL改成和下方一样的SQL,使得IDEA可以识别SQL方言呢&#xff1f; 1.选中SQL中的一部分代码&#xff0c;此时左侧会出现一个黄色的灯泡图案&#xff0c;点击2.选择这个注入语言或者引用

Spring Boot MongoDB自定义连接池配置

手打不易&#xff0c;如果转摘&#xff0c;请注明出处&#xff01; 注明原文&#xff1a;http://zhangxiaofan.blog.csdn.net/article/details/144341407 一、引言 在 Spring Boot 应用中使用 MongoDB 时&#xff0c;合理配置连接池可以显著提升数据库访问的性能和稳定性。默…

Tabnet介绍(Decision Manifolds)和PyTorch TabNet之TabNetRegressor

Tabnet介绍&#xff08;Decision Manifolds&#xff09;和PyTorch TabNet之TabNetRegressor Decision ManifoldsTabNet1.核心思想2. 架构组成3. 工作流程4. 优点 PyTorch TabNetTabNetRegressor参数1. 模型相关参数n_dn_an_stepsgammacat_idxscat_dimscat_emb_dim 2. 训练相关参…

图像变换方式区别对比(Opencv)

1. 变换示例 import cv2 import matplotlib.pyplot as plotimg cv2.imread(url) img_cut img[100:200, 200:300] img_rsize cv2.resize(img, (50, 50)) (hight,width) img.shape[:2] rotate_matrix cv2.getRotationMatrix2D((hight//2, width//2), 50, 1) img_wa cv2.wa…

Navicat分组、查询分享

1、分组 有些项目业务表比较多&#xff0c;多达几百张&#xff0c;如果通过人眼看&#xff0c;很容易头晕。这时候可以通过Navicat表分组来进行分类。 使用场景 按版本分组按业务功能分组 创建分组 示例&#xff1a;按版本分组&#xff0c;可以将1.0版本的表放到1.0中。 分组…

大模型在初治CLL成人患者诊疗全流程风险预测与方案制定中的应用研究

目录 一、绪论 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目的与内容 二、大模型技术与慢性淋巴细胞白血病相关知识 2.1 大模型技术原理与特点 2.2 慢性淋巴细胞白血病的病理生理与诊疗现状 三、术前风险预测与手术方案制定 3.1 术前数据收集与预处理 3.2 大模…

for循环的优化方式、循环的种类、使用及平替方案。

本篇文章主要围绕for循环,来讲解循环处理数据中常见的六种方式及其特点,性能。通过本篇文章你可以快速了解循环的概念,以及循环在实际使用过程中的调优方案。 作者:任聪聪 日期:2025年4月11日 一、循环的种类 1.1 默认有以下类型 原始 for 循环 for(i = 0;i<10;i++){…

穿透三层内网VPC1

网络拓扑: 打开入口web服务 信息收集发现漏洞CVE-2024-4577 PHP CGI Windows平台远程代码执行漏洞&#xff08;CVE-2024-4577&#xff09;复现_cve-2024-4577漏洞复现-CSDN博客 利用POC&#xff1a; 执行成功&#xff0c;那么直接上传马子&#xff0c;注意&#xff0c;这里要…

【计算机网络】同步操作 vs 异步操作:核心区别与实战场景解析

&#x1f4cc; 引言 在网络通信和分布式系统中&#xff0c;**同步&#xff08;Synchronous&#xff09;和异步&#xff08;Asynchronous&#xff09;**是两种基础却易混淆的操作模式。本文将通过代码示例、生活类比和对比表格&#xff0c;帮你彻底理解它们的区别与应用场景。 1…

TensorFlow充分并行化使用CPU

关键字&#xff1a;TensorFlow 并行化、TensorFlow CPU多线程 场景&#xff1a;在没有GPU或者GPU性能一般、环境不可用的机器上&#xff0c;对于多核CPU&#xff0c;有时TensorFlow或上层的Keras默认并没有完全利用机器的计算能力&#xff08;CPU占用没有接近100%&#xff09;…

Kubernetes容器编排与云原生实践

第一部分&#xff1a;Kubernetes基础架构与核心原理 第1章 容器技术的演进与Kubernetes的诞生 1.1 虚拟化技术的三次革命 物理机时代&#xff1a;资源浪费严重&#xff0c;利用率不足15% 虚拟机突破&#xff1a;VMware与Hyper-V实现硬件虚拟化&#xff0c;利用率提升至50% …

Windows 录音格式为什么是 M4A?M4A 怎样转为 MP3 格式

M4A 格式凭借其高效的压缩技术和卓越的音质表现脱颖而出&#xff0c;成为了包括 Windows 在内的众多操作系统默认的录音格式选择。然而&#xff0c;尽管 M4A 格式拥有诸多优点&#xff0c;不同的应用场景有时需要将这些文件转换为其他格式以满足特定需求。 本文将探讨 M4A 格式…

Qt之OpenGL使用Qt封装好的着色器和编译器

代码 #include "sunopengl.h"sunOpengl::sunOpengl(QWidget *parent) {}unsigned int VBO,VAO; float vertices[]{0.5f,0.5f,0.0f,0.5f,-0.5f,0.0f,-0.5f,-0.5f,0.0f,-0.5f,0.5f,0.0f };unsigned int indices[]{0,1,3,1,2,3, }; unsigned int EBO; sunOpengl::~sunO…

HCIP-17 BGP基础2

HCIP-17 BGP基础2 一、bgp的路由黑洞问题 1.bgp的同步功能 ipv4-family unicast IPV4的地址簇 undo synchronization 关闭BGP同步功能 bgp的同步功能原理 当边界路由器从ibgp邻居收到一条路由后&#xff0c;会使用该路由和igp路由表进行比较。 如果在igp路由表中存在…

leetcode_15. 三数之和_java

15. 三数之和https://leetcode.cn/problems/3sum/ 1、题目 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。…

Open Interpreter:重新定义人机交互的开源革命

引言 在人工智能技术蓬勃发展的今天&#xff0c;人机交互的方式正经历着前所未有的变革。Open Interpreter&#xff0c;作为一个开源项目&#xff0c;正在重新定义我们与计算机的互动方式。它允许大型语言模型&#xff08;LLMs&#xff09;在本地运行代码&#xff0c;通过自然…