• CompletableFuture 异常与事务【无标题】


    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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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(); //执行异步代码
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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(); //执行异步代码
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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; //异常点
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    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(); //执行异步代码
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    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); //执行异步代码
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    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);//提交
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    16666127597644

    目前还无法正常使用

  • 相关阅读:
    CCF计算机资格认证模拟题202212-1现值计算
    正规文法、正规式、确定的有穷自动机DFA、不确定的有穷自动机NFA 的概念、区分以及等价性转换【我直接拿下!】
    RKMEDIA--VI的使用
    VR航天科普主题公园模拟太空舱体验馆vr航天模拟体验设备
    Django 创建第一个项目
    虹科技术 | 不用外部Redbox如何无缝合并PRP和HSR网络实现精确时间同步?
    SpringBoot 使用 Sa-Token 完成权限认证
    “每周时事通讯:洞悉投资机会,把握市场脉搏 “
    Arctic 基于 Hive 的流批一体实践
    Linux操作系统的基础IO
  • 原文地址:https://blog.csdn.net/MXqihang/article/details/127669741