SpringBoot之Transactional事务传播行为

环境准备

sql语句

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL COMMENT '账户名',
  `money` double(11,2) NOT NULL COMMENT '金额',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='账号表';

初始数据
在这里插入图片描述
配置文件

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  mapper-locations: classpath*:/mapper/*Mapper.xml
  type-aliases-package: com.yzm.transactional.entity
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

启用事务管理

@Configuration
@MapperScan("com.yzm.transactional.mapper")
@EnableTransactionManagement
public class MybatisPlusConfig {
}

目录结构
在这里插入图片描述
以下示例中,A称为外方法,B称为内方法
AB方法不能在同一个Service中,这跟spring的事务实现机制有关
比如A方法在AccountService类中,B方法在BccountService类中

Propagation.REQUIRED

示例 11 正常转账

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA1() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB12();
        System.out.println("转账成功!");
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodB12() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

SQL执行流程
在这里插入图片描述
在这里插入图片描述
事务正常提交,金额改变。

示例 12 外方法异常

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA1() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB12();
        System.out.println("转账成功!");
        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodB12() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);
    }

在这里插入图片描述
在这里插入图片描述
外方法有异常,未显示事务提交,且金额不变,说明事务回滚了

示例 13 内方法异常

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA1() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB12();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodB12() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
内方法有异常,未显示事务提交,且金额不变,说明事务回滚了

从上面三个示例可以看出:
REQUIRED修饰的内外方法是在同一个事务中的,只要其中一个方法抛出异常,整个事务就会回滚。

示例 14 内方法不加 @Transactional 注解,并有异常

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA1() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB12();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodB12() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

结果跟 @示例 13 是一样的
内方法没有注解,但能被外方法的事务包裹,使得内外方法始终在同一事务中。

示例 15 外方法不加 @Transactional 注解,并内方法有异常

    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA1() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB12();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodB12() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
外方法以非事务方式运行的,小王钱少了200
内方法有异常,小明钱没变,说明事务回滚了

示例 16 平级内方法

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA1() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB12();
        bccountService.methodB13();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodB12() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 100);
        updateById(xming);

//        int i = 1 / 0;
    }

    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodB13() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 100);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
内方法B13有异常,金额不变,说明3个方法都在同一事物中,有异常导致整个事务回滚

如果是嵌套内方法也是一样的,都在同一事务中。
总结:

默认,最常用的;
支持事务,当前存在事务则加入,不存在就创建事务;
最外层方法必须加事务注解,里层方法可加可不加(不加注解的里层方法会被外层事务包裹);
外层方法和里层包裹的方法始终在同一事务中,只要任意一个方法抛出异常(未捕获),整个事务就会回滚。

Propagation.SUPPORTS

恢复成初始数据
在这里插入图片描述

示例 21 外方法REQUIRED、内方法SUPPORTS并有异常

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA2() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB22();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public void methodB22() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
外方法创建事务,内方法(支持事务)加入该事务,使得内外方法处于同一事务中,内方法抛出异常,导致整个事务回滚,金额不变。

示例 22 外方法不加 @Transactional 注解,内方法SUPPORTS

    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA2() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB22();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public void methodB22() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
外方法以非事务方式运行,小王钱少了200
内方法有异常,未显示事务提交,小明钱多了200,说明内方法没有事务,也是以非事务方式运行

示例 23 内外都是SUPPORTS,内方法有异常

    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public void methodA2() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB22();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public void methodB22() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
内方法有异常,未显示事务提交,但是金额都变了,说明是以非事务方式运行

示例 24 外方法SUPPORTS,内方法REQUIRED,内外都有异常

    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public void methodA2() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB22();
        System.out.println("转账成功!");
        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodB22() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
外方法有异常,小王钱少了200,说明没有事务,以非事务方式运行
内方法有异常,小明钱没变,说明内方法自己创建了一个事务,同时也证实了外方法没有事务,不然内方法一定会加入到外方法的事务中
总结:

少见少用;
支持当前事务,有事务就加入事务,没有事务就以非事务方式运行;
单独调用或最外层方法是SUPPORTS,都是以非事务方式运行,有异常不回滚。

Propagation.MANDATORY

恢复初始数据
在这里插入图片描述

示例 31 外方法REQUIRED、内方法MANDATORY

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA3() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB32();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
    public void methodB32() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

跟 示例 21 一样
外方法创建事务,内方法(支持事务)加入外方法事务,同一事务,事务回滚,金额不变。

示例 32 外方法不加 @Transactional 注解,内方法MANDATORY

    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA3() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB32();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
    public void methodB32() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
外层以非事务方式运行,小王钱少了
内方法直接报错

示例 33 内外都是MANDATORY(或者内方法是REQUIRED)

在这里插入图片描述
都是直接报错

总结:

少见少用;
支持当前事务,有事务则加入事务,没有事务就会抛出异常,显示错误信息。
单独调用或者最外层方法是MANDATORY,就直接报错

Propagation.REQUIRES_NEW

恢复初始数据
在这里插入图片描述

示例 41 外方法REQUIRED、内方法REQUIRES_NEW,外方法有异常

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA4() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB42();
        System.out.println("转账成功!");
        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodB42() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

//        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
小王钱不变小明钱多了200
外方法创建外事务,内方法创建内事务,外方法有异常,只会回滚外事务,内事务正常提交。

示例 42 外方法REQUIRED、内方法REQUIRES_NEW,内方法有异常

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA4() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB42();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodB42() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
金额都不变
外方法创建外事务,无异常;
内方法创建内事务,有异常导致内事务回滚,同时也让外事务回滚

示例 43 外方法REQUIRES_NEW、内方法REQUIRED,外方法有异常

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodA4() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB42();
        System.out.println("转账成功!");
        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodB42() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

//        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
金额都不变
外方法创建事务后,内方法就不再创建事务而是加入到外方法的事务中,同一事务,外异常,就回滚

改成内异常也是整个事务回滚。

示例 44 外内方法都是REQUIRES_NEW,外方法有异常

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodA4() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB42();
        System.out.println("转账成功!");
        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodB42() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

//        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
小王钱不变,小明钱凭空多了200
跟 示例 41 是一样的,内外方法都有自己的事务,外方法有异常外事务回滚,内事务不影响

示例 45 外内方法都是REQUIRES_NEW,内方法有异常

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodA4() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB42();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodB42() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
金额都不变
跟 示例 42 是一样的,内外方法都有自己的事务,内方法有异常导致内事务回滚,外事务也跟着回滚

示例 46 平级内方法

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodA4() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB42();
        bccountService.methodB43();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodB42() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 100);
        updateById(xming);

//        int i = 1 / 0;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodB43() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 100);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
小王钱不变,小明两次收钱,只有一次成功收到钱加了100
A外事务,B1、B2内事务(平级关系);
B2异常回滚,能影响A外事务回滚,但不影响B1事务提交

示例 47 嵌套内方法

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodA4() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB42();
        System.out.println("转账成功!");
//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodB42() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 100);
        updateById(xming);

        cccountService.methodC44();
        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void methodC44() {
        Account xming = getById(3);
        xming.setMoney(xming.getMoney() + 100);
        updateById(xming);

//        int i = 1 / 0;
    }

A(祖父级) 包含 B(父级) 包含 C(子级),父级B异常
注意:C的SQL内容不能对小明进行修改,跟B的SQL内容对冲,会报错"Lock wait timeout exceeded; try restarting transaction",新增小马用户。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
小王钱不变,小明钱也没变,小马钱多了100
父级B异常,自身事务回滚,子级C事务不被B影响正常提交,祖父级A事务被B影响也回滚

如果是子级C异常,那么3个事务都回滚
总结:

常见常用;
无论当前有没有事务,都始终自己创建新事务;
平级或嵌套事务时,异常事务回滚,父级和父级以上的外层事务也跟着回滚,但平级跟子级事务不影响正常提交。

Propagation.NOT_SUPPORTED

在这里插入图片描述

示例 51 外方法REQUIRED、内方法NOT_SUPPORTED,都有异常

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA5() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB52();
        System.out.println("转账成功!");
        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, rollbackFor = Exception.class)
    public void methodB52() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
小王钱不变,小明钱多了200
外方法有异常,能回滚,有事务;内方法有异常,不能回滚,说明没有事务
总结:

少见少用;
不支持当前事务,无论有没有事务,都是以非事务方式运行

Propagation.NEVER

示例 61 外方法REQUIRED、内方法NEVER

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA6() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB62();
        System.out.println("转账成功!");
    }
    @Override
    @Transactional(propagation = Propagation.NEVER, rollbackFor = Exception.class)
    public void methodB62() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);
    }

在这里插入图片描述
外方法有事务,内方法被NEVER修饰,直接报错
总结:

少见少用;
不支持事务,只要有事务就报错,始终以非事务方式运行

Propagation.NESTED

在这里插入图片描述

示例 71 外方法REQUIRED、内方法NESTED,外方法异常

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA7() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB72();
        System.out.println("转账成功!");

        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.NESTED, rollbackFor = Exception.class)
    public void methodB72() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

//        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
金额不变
外方法创建外事务,内方法不是加入到外事务中,而是在外事务里面再创建一个子事务,嵌套在外事务里;
此时外事务异常回滚,嵌套子事务也跟着回滚。

示例 72 外方法REQUIRED、内方法NESTED,内方法异常

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA7() {
        Account xwang = getById(1);
        xwang.setMoney(xwang.getMoney() - 200);
        updateById(xwang);

        bccountService.methodB72();
        System.out.println("转账成功!");

//        int i = 1 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.NESTED, rollbackFor = Exception.class)
    public void methodB72() {
        Account xming = getById(2);
        xming.setMoney(xming.getMoney() + 200);
        updateById(xming);

        int i = 1 / 0;
    }

在这里插入图片描述
在这里插入图片描述
金额不变
外方法创建外事务,内方法创建外事务的嵌套子事务,子事务有异常回滚了,也会导致外事务回滚
总结:

常见常用;
当前存在事务,则在该事务里面创建一个嵌套子事务运行;
当前没有事务,NESTED就等同于REQUIRED属性。

比较REQUIRED、REQUIRES_NEW和NESTED属性

定义serviceA.methodA()以PROPAGATION_REQUIRED修饰;
定义serviceB.methodB()以表格中三种方式修饰;
methodA中调用methodB

异常状态PROPAGATION_REQUIREDPROPAGATION_REQUIRES_NEWPROPAGATION_NESTED
事务同一事务两个独立事务B事务嵌套在A事务中
A正常B正常AB一起提交B先提交,A再提交AB一起提交
A异常B正常AB一起回滚B先提交,A再回滚AB一起回滚
A正常B异常AB一起回滚B先回滚;A再回滚AB一起回滚
A异常B异常AB一起回滚B先回滚,A再回滚AB一起回滚
  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值