java多线程事务处理

2023-11-03

1.自定义事务管理器

@Component
public class SelfTransactionManager {
    private TransactionStatus transactionStatus;
    //获取事务源
    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Autowired
    private TransactionDefinition transactionDefinition;
    /**
     * 手动开启事务
     */
    public TransactionStatus begin() {
        transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
        return transactionStatus;
    }

    /**
     * 提交事务
     */
    public void commit(TransactionStatus transactionStatus) {
        platformTransactionManager.commit(transactionStatus);
    }

    /**
     * 回滚事务
     */
    public void rollBack() {
        platformTransactionManager.rollback(transactionStatus);
    }
}

2.业务中实现

@Service
@AllArgsConstructor
public class BookingInfoServiceImpl implements IBookingInfoService {

    private final BookingInfoMapper bookingInfoMapper;
    private final SelfTransactionManager selfTransactionManager;
    private final TaskExecutor taskExecutor;//自定义的线程池

    @Override
    @Transactional(rollbackFor=Exception.class)
    public boolean test() {
        // 主线程决策状态(决策最终是commit还是rollback)
        AtomicBoolean IS_OK = new AtomicBoolean(true);
        // 假设子线程数量为1个(根据自己的业务需求)
        final int size = 1;
        // 子线程计数器
        CountDownLatch childMonitor = new CountDownLatch(size);
        // 子线程结果集
        CopyOnWriteArrayList<Boolean> childResponse = new CopyOnWriteArrayList<>();
        // 主线程计数器
        CountDownLatch mainMonitor = new CountDownLatch(1);

    	/**
		 * ================================子线程1=======================================
		 */
        CompletableFuture.runAsync(() -> {
            TransactionStatus transactionStatus = selfTransactionManager.begin();
            boolean result = false;
            try {
                // 当前子线程开始插入数据
                // ---------业务代码----------
                BookingInfo bookingInfo = new BookingInfo();
                bookingInfo.setCreateTime(DateUtil.date());
                bookingInfo.setPhoneNumber("13215592666");
                bookingInfo.setNickName("ceshi0");
                result = bookingInfoMapper.insertBookingInfo(bookingInfo) < 1 ? false : true;
                // ---------业务代码----------
                
                / /插入结果 true or false
                childResponse.add(result);
                // 执行到这里,等待主线程执行完,因为当前子线程要拿到 IS_OK 的结果,IS_OK的结果由主线程决策
                mainMonitor.await();
                // 根据主线程决策的IS_OK,判断是回滚还是提交
                if (IS_OK.get()) {
                    // 提交
                    selfTransactionManager.commit(transactionStatus);
                }else {
                    // 回滚
                    selfTransactionManager.rollBack();
                }
            } catch (Exception e) {
                e.printStackTrace();
                // 因为会发生异常 而主线程一直在 while (true) 循环 childResponse的size,这里一定要保证进行add,否则可能会出现死循环
                childResponse.add(result);
                // 异常回滚
                selfTransactionManager.rollBack();
            } finally {
                // 子线程执行完计数器-1
                childMonitor.countDown();
            }
        }, taskExecutor);


    	/**
		 * ================================主线程========================================
		 */
        try {
            // ---------业务代码----------
            BookingInfo bookingInfo2 = new BookingInfo();
            bookingInfo2.setPhoneNumber("13215592000");
            bookingInfo2.setNickName("ceshi2");
            bookingInfo2.setCreateTime(new Date());
            boolean result = bookingInfoMapper.insertBookingInfo(bookingInfo2) < 1 ? false : true;
            // ---------业务代码----------
            
            // 主线程插入不成功,不成功让 IS_OK = false;
            if (!result) {
                throw new RuntimeException();
            }

            // 循环获取子线程结果
            while (true) {
                if (childResponse.size() == size) {
                    break;
                }
            }

            // 子线程中存在不成功让 IS_OK = false;
            if (childResponse.contains(Boolean.FALSE)) {
                throw new RuntimeException();
            }

        } catch (Exception e) {
            e.printStackTrace();
            // IS_OK = false; 等待主线程走完子线程就能得知 IS_OK 为false
            IS_OK.set(Boolean.FALSE);
            // 这里抛出异常 是为了当前主线程事务自动进行回滚
            throw e;
        } finally {
            // 到这个方法执行完就意味着mainMonitor中主线程走完了,接着子线程会开始执行
            mainMonitor.countDown();
        }

        return true;
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java多线程事务处理 的相关文章

随机推荐

  • 产品经理不懂技术的后果很严重

    目前产品研发的流程中分工越来越细 很多公司都将产品和研发进行了分离 产品负责需求的分析和产品的设计 很多产品并不懂技术 而且由于这种分离很多时候都是用跨部门来设定的 因此产品和技术的沟通很难 这就导致了以下普遍存在的问题 1 系统的扩展性非
  • MySQL用户权限及管理

    一 mysql创建用户 1 创建用户 mysql gt create user test identified by 123456 创建了用户 但是没有任何权限 Query OK 0 rows affected 0 00 sec mysql
  • JAVA线程同步

    线程同步 线程同步 即当有一个线程在对内存进行操作时 其他线程都不可以对这个内存地址进行操作 直到该线程完成操作 其他线程才能对该内存地址进行操作 而其他线程又处于等待状态 实现线程同步的方法有很多 为什么要创建多线程 在一般情况下 创建一
  • Python3实现一个简单的接口服务实现跨域请求

    使用Python实现一个简单的接口服务 可以通过get post方法请求该接口 拿到响应数据 创建一个api server py文件 添加代码如下 import json from flask import request Flask im
  • python+selenium+unittest+HTMLTestRunner读取csv文件参数化登陆测试

    之前尝试了Python selenium unittest HTMLTestRunner 传送门 写了登陆脚本 然后又看了参数化及循环 于是决定写个参数化的登陆脚本 当然遇到问题是在所难免的 几经周折 最后还是完成了参数化脚本 所以写下本帖
  • 求最大公约数的三种算法(java实现)

    目录 一 连续整数检测算法 二 欧几里得算法 三 分解质因数 一 连续整数检测算法 1 t min m n 2 m 除以t 如果余数为0 则执行步骤3 否则 执行第4 步 3 n 除以t 如果余数为0 返回t 的值作为结果 否则 执行第4
  • 用递归算法遍历一个目录,打印所有文件的名字

    用递归算法遍历一个目录 打印所有文件的名字 import os def walk dirname for name in os listdir dirname 遍历形参文件中的名字 path os path join dirname nam
  • AIX命令集锦九(TCP/IP网络管理命令)

    9 1 主机名修改命令hostname uname n 显示主机名uname x uname a uname u 显示操作系统的详细信息 显示系统IDhostname 主机名 这样改的主机名只能保持到下次重起smit hostname 或c
  • pycharm: unused import statement错误解决方法

    在pycharm中导入numpy包等 有时候字体都呈现灰色 看提示为 unused import statement 如果出现上述问题 可以从以下几个方面进行尝试 1 Pycharm file 菜单下有Invalidate caches R
  • 数据仓库——分层原理

    目录 一 什么是数据仓库 二 数仓建模的意义 为什么要对数据仓库分层 三 ETL 四 技术架构 五 数仓分层架构 数仓逻辑分层 1 数据引入层 ODS Operational Data Store 又称数据基础层 1 1 数据主要来源 1
  • php mail 权限,PHP mail()函数漏洞总结 · MYZ’s Blog

    漏洞成因 email protected golunski曝光了多个使用PHP mail函数引发命令执行的漏洞 众多使用php内置mail函数的第三方邮件库 如phpmailer SwiftMailer 纷纷中招 这些漏洞的成因和之前曝光的
  • 区块链+保险,落地还有多远?

    以前的区块链还在和炒币紧紧相连 现在 区块链就已经在去币化的路上越走越远 如今 已迅速渗透到保险行业 从风控 运营 再保险等方面影响保险公司的效率和商业模式 随着区块链技术的日益发展 已有不少保险巨头和新兴创业公司开始使用区块链技术来防范保
  • 大数据相关技术学习

    https github com lishuai2016 ls bigdata learn
  • 硬十宝典学习笔记_各种地

    1 定义 GND 指的是电线接地端的简写 代表地线或0线 作为电路或系统基准的等电位点或平面 电路图上和电路板上的GND Ground 代表地线或0线 GND就是公共端的意思 也可以说是地 但这个地并不是真正意义上的地 是出于应用而假设的一
  • iOS学习笔记二——OC代码规范(上)

    文章目录 一 规范格式 1 1 规范的head file格式 1 2 规范的source file格式 二 命名要求 2 1 功能明确 2 2 保持一致性 2 3 使用前缀 2 4 排版惯例 2 5 Class和Protocal 2 6 文
  • html的tab只显示第一个,tab切换+下拉刷新+只有第一个tab有效,第二个tab下拉刷新出来的内容跑到第一个去了 怎么解决 求解答...

    mui table view li overflow hidden margin 1 25rem 3 0 border radius 0 21rem background color FFFFFF i da background url i
  • springboot shardingjdbc与druid数据源冲突解决

    首先看错误信息 cancelling refresh attempt org springframework beans factory BeanCreationException Error creating bean with name
  • JAVA锁机制常见面试题

    synchronized与Lock的区别 synchronied 是关键字 Lock 是接口 synchronied可以修饰方法 代码块 Lock只能修饰代码块 synchronized自动加锁解锁 lock 需要手动加锁解锁 synchr
  • 初级测试小宝典 测试流程,不能复现bug,开发不认为是bug级2020测试点的热点提问的回答

    1 测试流程 1 按阶段划分为 单元测试 集成测试 系统测试 验收测试 2 按是否运行 静态测试 动态测试 3 按是否查看源代码 自盒测试 黑盒测试 功能测试 逻辑功能测试 界面测试 易用性测试 安装测试 兼容性测试 性能测试 一般性能测试
  • java多线程事务处理

    1 自定义事务管理器 Component public class SelfTransactionManager private TransactionStatus transactionStatus 获取事务源 Autowired pri