CompletableFuture 异常与事务【无标题】

本文通过多个场景测试探讨了在Java中使用CompletableFuture结合编程式事务处理时遇到的问题,特别是异步任务中如何正确实现事务回滚。文章详细记录了不同场景下的尝试与结果,并分析了事务与线程绑定所带来的挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TODO 网上关于 多线程的文章大多都是 2个线程直线的事务,3个线程开始事务,要自己编写,作者比较菜,写不清白线程的唤醒与休眠

CompletableFuture 异常与事务

测试执行顺序

场景一 -无效

    void saveException() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            //异常出现也会执行
            UserVO vo = UserVO.builder().age(20).name("异常保存测试-会执行语句1").build();
            service.save(vo);
            int i = 1/0; //出现异常但是不会回滚
        }, THREAD_POOL);

        future.get(); //执行异步代码
        UserVO vo = UserVO.builder().age(20).name("异常保存测试-不会执行语句").build();
        service.save(vo);
    }

16664040105230

场景二 -无效

void save02Exception() throws Exception {
    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        //异常出现也会执行
        UserVO vo = UserVO.builder().age(20).name("异常保存测试-会执行语句1").build();
        service.save(vo);
        int i = 1/0; //出现异常但是不会回滚
    }, THREAD_POOL);

    UserVO vo = UserVO.builder().age(20).name("异常保存测试-会执行语句2").build();
    service.save(vo);
    future.get(); //执行异步代码
}

16664042174716

场景三 -无效

    @Test
    @Transactional
    void save02Exception() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            //异常出现也会执行
            UserVO vo = UserVO.builder().age(20).name("异常保存测试-会执行语句1").build();
            service.save(vo);
            int i = 1/0; //出现异常但是不会回滚
        }, THREAD_POOL);

        UserVO vo = UserVO.builder().age(20).name("异常保存测试-异常后回滚").build();
        service.save(vo);
        future.get(); //执行异步代码
    }

16664045524238

场景四 -无效

    @Test
    @Transactional
    void save04Exception() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            //异常出现也会执行
            UserVO vo = UserVO.builder().age(20).name("异常保存测试-会执行语句1").build();
            service.save(vo);
        }, THREAD_POOL);
        UserVO vo = UserVO.builder().age(20).name("异常保存测试-异常后回滚").build();
        service.save(vo);
        future.get(); //执行异步代码
        int i = 1/0; //异常点
    }

16664052867054

使用 exceptionlly - 无效

    @Test
    @Transactional
    void save03Exception() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            //异常出现也会执行
            UserVO vo = UserVO.builder().age(20).name("异常保存测试-会执行语句1").build();
            service.save(vo);
            int i = 1/0; //异常点
        }, THREAD_POOL)
                .exceptionally(throwable -> {
                    //捕获异常做处理 却不能回滚事务
                    log.error("捕获到异常");
                    return null;
                });
        UserVO vo = UserVO.builder().age(20).name("异常保存测试-异常后回滚").build();
        service.save(vo);
        future.get(); //执行异步代码
    }

16664048734000

手动设置事务 - 主线 1-1 子线程 -编程式事务

      /**
     * 主线程 1-1 子线程 事务回滚 PROPAGATION_REQUIRES_NEW
     * 外层事务 未提交
     * @throws Exception
     */
		@Test
    @Transactional(rollbackFor = Exception.class)
    void save05Exception() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            //创建事务 内部事务
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            def.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus status = dataSourceTransactionManager.getTransaction(def);
            //异常出现也会执行
            UserVO vo = UserVO.builder().age(20).name("异步线程-回滚数据").build();
            try {
                service.save(vo);
                int i = 1 / 0; //异常点
            } catch (Exception e){
                dataSourceTransactionManager.rollback(status);
                throw new RuntimeException();
            }
            dataSourceTransactionManager.commit(status);
        }, THREAD_POOL).exceptionally(
                throwable->{
            throw new RuntimeException("捕获线程内部异常,抛出");
        });
        UserVO vo = UserVO.builder().age(21).name("主线程-异常后回滚").build();
        service.save(vo);
        future.get(4,TimeUnit.SECONDS); //执行异步代码
    }

16664183421180

编程式事务

    /**
     * 主线程异常 ,异步线程无法回滚
     * @throws Exception
     */
    @Test
    //@Transactional(rollbackFor = Exception.class)
    void save06Exception() throws Exception {
        //外层事务
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = dataSourceTransactionManager.getTransaction(def);

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            //创建事务 内部事务
            DefaultTransactionDefinition defNei = new DefaultTransactionDefinition();
            defNei.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
            TransactionStatus transaction = dataSourceTransactionManager.getTransaction(defNei);

            //异常出现也会执行
            UserVO vo = UserVO.builder().age(20).name("异步线程-回滚数据").build();
            try {
                service.save(vo);
                //int i = 1 / 0; //异常点
            }catch (Exception e){
                dataSourceTransactionManager.rollback(transaction);
                throw new RuntimeException("内存抛出异常");
            }

            dataSourceTransactionManager.commit(transaction);
        }, THREAD_POOL).exceptionally(throwable -> {
            throw new RuntimeException("内存抛出异常");
        });
        UserVO vo = UserVO.builder().age(21).name("主线程-异常后回滚").build();
        service.save(vo);
        int i = 1 / 0; //异常点
        future.get(4,TimeUnit.SECONDS); //执行异步代码
        boolean completedExceptionally = future.isCompletedExceptionally();
        if(completedExceptionally){
            throw new RuntimeException("主线程异常");
        }
        dataSourceTransactionManager.commit(status);//提交
    }

16664238147265

意识到问题,是事务跟线程绑定,线程死亡,主线线程,无法操作子线程,作为思路,继续改写代码

get 为分界点回滚事务

    /**
     *  以get 为分解 回滚事务
     * @throws Exception
     */
    @Test
    void save07Exception() throws Exception {

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            //外层事务
            DefaultTransactionDefinition defNei = new DefaultTransactionDefinition();
            defNei.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus statusNei = dataSourceTransactionManager.getTransaction(defNei);

            //异常出现也会执行
            UserVO vo = UserVO.builder().age(20).name("异常保存测试-数据会保存").build();
            try {
                service.save(vo);
                //int i = 1/0; //出现异常 会回滚
            }catch (Exception e){
                dataSourceTransactionManager.rollback(statusNei);
                throw new RuntimeException("抛出异常");
            }
            dataSourceTransactionManager.commit(statusNei);
        }, THREAD_POOL);

        //int i = 1/0; //出现异常 会回滚
        Void unused = future.get();//执行异步代码 这行代码非常重要 关系到异常
        int i = 1/0; //出现异常 回滚失效,应为异步线程已经在get时消亡了 (估计)
        UserVO vo = UserVO.builder().age(20).name("异常保存测试-数据不会保存").build();
        service.save(vo);
    }

16666121205847

get之后 内部线程消亡,主线程,发生异常内部事务不会回滚

这里因该也可自己去写线程的,睡眠唤醒,来实现多个 任务之间的事务回滚。本人技术渣,写不明白。

更加复杂的场景

   /**
     * 失败案例
     * @throws Exception
     */
    @Test
    void save08Exception() throws Exception {

        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            //外层事务
            DefaultTransactionDefinition defNei = new DefaultTransactionDefinition();
            defNei.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus statusNei = dataSourceTransactionManager.getTransaction(defNei);
            //异常出现也会执行
            UserVO vo = UserVO.builder().age(20).name("异步线程1-数据会保存").build();
            try {
                service.save(vo);
                //int i = 1/0; //出现异常 会回滚 异步线程2 不会回滚
            }catch (Exception e){
                dataSourceTransactionManager.rollback(statusNei);
                throw new RuntimeException("抛出异常");
            }
            dataSourceTransactionManager.commit(statusNei);
        }, THREAD_POOL);

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            //外层事务
            DefaultTransactionDefinition defNei = new DefaultTransactionDefinition();
            defNei.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus statusNei = dataSourceTransactionManager.getTransaction(defNei);
            //异常出现也会执行
            UserVO vo = UserVO.builder().age(30).name("异步线程2-数据会保存").build();
            try {
                service.save(vo);
                int i = 1/0; //出现异常 会回滚  异步线程1 不会回滚
            }catch (Exception e){
                dataSourceTransactionManager.rollback(statusNei);
                throw new RuntimeException("抛出异常");
            }
            dataSourceTransactionManager.commit(statusNei);
        }, THREAD_POOL);
        
        //int i = 1/0; //出现异常 会回滚
        Void unused = CompletableFuture.allOf(future1, future2).get();//执行异步代码  这行代码非常重要 关系到异常
        //int i = 1/0; //出现异常 回滚失效,应为异步线程已经在get时消亡了 (估计)
        UserVO vo = UserVO.builder().age(10).name("主线程-数据不会保存").build();
        service.save(vo);
    }

16666127597644

目前还无法正常使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值