Spring事务传播机制详解和 @Transactional 失效情况原因及解决方法

视频出处:https://www.bilibili.com/video/BV1te4y1J7Qd/?vd_source=44d1426ea434f76dfe83b4aa384fb2fa

1、什么是事务传播机制

事务的传播,是A方法调用B方法并将事务传递给它。事务的转播机制主要针对被调用者而言,控制它是否被传播或者被怎样传播。spring事务的传播机制有七种:

传播行为描述
PROPAGATION_REQUIRED默认的Spring事物传播级别,若当前存在事务,则加入该事务,若不存在事务,则新建一个事务
PROPAGATION_REQUIRE_NEW若当前没有事务,则新建一个事务。若当前存在事务,则新建一个事务,新老事务相互独立。外部事务抛出异常回滚不会影响内部事务的正常提交
PROPAGATION_NESTED如果当前存在事务,则嵌套在当前事务中执行。如果当前没有事务, 则新建一个事务,类似于REQUIRE_NEW
PROPAGATION_SUPPORTS支持当前事务,若当前不存在事务,以非事务的方式执行
PROPAGATION_NOT_SUPPORTED以非事务的方式执行,若当前存在事务,则把当前事务挂起
PROPAGATION_MANDATORY强制事务执行,若当前不存在事务,则抛出异常
PROPAGATION_NEVER以非事务的方式执行,如果当前存在事务,则抛出异常

传播级别一般不需要定义,默认就是PROPAGATION_REQUIRED,除非在嵌套事务的情况。上述描述表格的描述还是比较抽象,下面我们使用一个例子来说明这个传播机制。假定方法A调用方法B:

方法B定义的事务类型A方法有事务时A方法无事务
@Transactional(propagation = Propagation.REQUIRED)B和A事务合并成一个事务B新建一个事务
@Transactional(propagation = Propagation.REQUIRES_NEW)B新建一个事务,和A事务无关,互不影响(A回滚不会影响到B的提交)B新建一个事务
@Transactional(propagation = Propagation.NESTED)B新建一个A的子事务,A回滚会导致B已经提交的事务一起回滚;B回滚不会影响到AB新建一个事务
@Transactional(propagation = Propagation.SUPPORTS)B加入到A事务中B无事务
@Transactional(propagation = Propagation.NOT_SUPPORTED)挂起A事务,B以无事务方式执行B无事务
@Transactional(propagation = Propagation.MANDATORY)B加入到A事务中B抛异常
@Transactional(propagation = Propagation.NEVER)B抛异常B无事务

2、七种事务传播机制

现在在这里,我们假定方法AStudentService类中的方法,方法BCourseService类中的方法

2.1、@Transactional(propagation = Propagation.REQUIRED)

A中没有事务,B中有事务


@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //这里没有开启事务,courseService.insertCourse会自己开启一个事务运行
    //而且两个添加操作都会成功,因为studentMapper.insert(student);是自动提交的
    public void insert0(){

        courseService.insertCourse();

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);


        int i = 1/0;//这里抛出异常,两个添加操作都不会回滚
    }

}


@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.REQUIRED)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}

A和B两个方法都有事务

@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //两个方法都使用了@Transactional(propagation = Propagation.REQUIRED)
    //courseService.insertCourse()会加入到insert0方法开启的事务中,所以两个方法在同一事务中
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){

        courseService.insertCourse();

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);


        int i = 1/0;//这里抛出异常,两个添加操作都被回滚
    }
    
}


@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.REQUIRED)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}


2.2、@Transactional(propagation = Propagation.REQUIRES_NEW)

在A方法的事务中抛出异常,B方法正确执行,正常提交

@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //courseService.insertCourse()方法用了@Transactional(propagation = Propagation.REQUIRES_NEW)
    //开启了一个独立的新的事务,在独立的事务中运行,
    // 并且insert0()开启的事务被挂起
    //等courseService.insertCourse()运行完毕,再恢复insert0()的事务
    //两个事务的提交和回滚都在各自事务中完成
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){

        courseService.insertCourse();

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);


        //这里抛出异常,courseService.insertCourse()不会回滚
        //但是studentMapper.insert会被回滚
        int i = 1/0;
    }

}

@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}


在B方法中抛出异常,A和B都被回滚


@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //courseService.insertCourse()方法用了@Transactional(propagation = Propagation.REQUIRES_NEW)
    //courseService.insertCourse()会抛出异常给insert0()方法,导致两个方法都被回滚
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);
        //这里调用的insertCourse会抛出异常
        courseService.insertCourse();


    }

}


@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);
        //这里抛出异常,异常会被抛给调用这个方法的调用者
        int i = 1/0;
    }
}

2.3、@Transactional(propagation = Propagation.SUPPORTS)

A方法有事务,B加入到事务中

@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //由于courseService.insertCourse使用@Transactional(propagation = Propagation.SUPPORTS)
    //所以会加入到insert0()开启的事务中,被一起回滚
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){

        courseService.insertCourse();

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);

        //这里抛出异常,courseService.insertCourse()也会被回滚
        int i=1/0;


    }

}



@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.SUPPORTS)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}

A没有事务,B以无事务方式运行

@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //由于courseService.insertCourse使用@Transactional(propagation = Propagation.SUPPORTS)
    //由于insert0没有开启事务,所以两个方法都以无事务方式运行,都会自动提交
    public void insert0(){

        courseService.insertCourse();

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);

        //这里抛出异常,courseService.insertCourse()不会被回滚
        //studentMapper.insert(student);也不会被回滚
        int i=1/0;


    }

}



@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.SUPPORTS)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}

2.4、@Transactional(propagation = Propagation.NOT_SUPPORTED)

A有事务,B以无事务方式运行(自动提交)

@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //由于courseService.insertCourse使用@Transactional(propagation = Propagation.NOT_SUPPORTED)
    //所以courseService.insertCourse会以无事务方式运行,自动提交
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){

        courseService.insertCourse();

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);

        //这里抛出异常,courseService.insertCourse()不会被回滚
        //studentMapper.insert(student);会被回滚
        int i=1/0;


    }

}

@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}


2.5、@Transactional(propagation = Propagation.MANDATORY)

A有事务,B加入事务中

@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //由于courseService.insertCourse使用@Transactional(propagation = Propagation.MANDATORY)
    //所以courseService.insertCourse会加入到insert0()的事务中,一起回滚
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){

        courseService.insertCourse();

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);

        //这里抛出异常,courseService.insertCourse()会被回滚
        //studentMapper.insert(student);会被回滚
        int i=1/0;

    }
    
   
}


@Service
public class CourseService {


    @Autowired
    private CourseMapper courseMapper;

    @Transactional(propagation = Propagation.MANDATORY)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}

A没有事务,B会抛出异常


@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //由于courseService.insertCourse使用@Transactional(propagation = Propagation.MANDATORY)
    //courseService.insertCourse();会抛出异常
    public void insert0(){

        courseService.insertCourse();

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);

    }

}



@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.MANDATORY)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}


2.6、@Transactional(propagation = Propagation.NEVER)

A方法无事务,A和B都以无事务方式运行

@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //由于courseService.insertCourse使用@Transactional(propagation = Propagation.NEVER)
    //courseService.insertCourse();以无事务方式运行,两个添加都不会被回滚
    public void insert0(){

        courseService.insertCourse();

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);

        //这里抛出异常,但是两个添加操作都是自动提交的,都不会被回滚
        int i = 1/0;

    }

}

@Service
public class CourseService {


    @Autowired
    private CourseMapper courseMapper;

    @Transactional(propagation = Propagation.NEVER)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}


A方法有事务,B抛出异常

@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //由于courseService.insertCourse使用@Transactional(propagation = Propagation.NEVER)
    //由于insert0()开启了一个事务,所以courseService.insertCourse();会抛出异常
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){



        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);

        //这里会抛出异常,因为courseService.insertCourse不支持事务
        courseService.insertCourse();

    }

}



@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.NEVER)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}

2.7、@Transactional(propagation = Propagation.NESTED)

A方法抛出异常,B方法成功的提交也被回滚

@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //由于courseService.insertCourse使用@Transactional(propagation = Propagation.NESTED)
    //由于insert0()开启了一个事务,所以courseService.insertCourse();在嵌套事务内层运行
    //当courseService.insertCourse()成功提交后,insert0()最后抛出异常,会导致courseService.insertCourse()也会被回滚
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){

        try {
            courseService.insertCourse();
        } catch (Exception e) {
            e.printStackTrace();
        }

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);

        //这里抛出异常会导致courseService.insertCourse()成功的提交也被回滚
        //studentMapper.insert(student)提交的也会被回滚
        int i = 1/0;
    }

}




@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.NESTED)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);


    }
}

A方法执行成功,B方法抛出异常,只有B的提交被回滚,A的提交成功执行



@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //由于courseService.insertCourse使用@Transactional(propagation = Propagation.NESTED)
    //由于insert0()开启了一个事务,所以courseService.insertCourse();在嵌套事务内层运行
    //当courseService.insertCourse()抛出异常会被catch,insert0会成功执行
    //最后,insert0成功提交,courseService.insertCourse()被回滚了
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){

        try {
            courseService.insertCourse();
        } catch (Exception e) {
            e.printStackTrace();
        }

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);


    }

}



@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.NESTED)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);
        //这个方法抛出异常,只会回滚当前这个方法
        int i = 1/0;
    }
}


A方法提交成功,B方法也提交成功


@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;



    //由于courseService.insertCourse使用@Transactional(propagation = Propagation.NESTED)
    //由于insert0()开启了一个事务,所以courseService.insertCourse();在嵌套事务内层运行
    //当courseService.insertCourse()抛出异常会被catch,insert0会成功执行
    //最后,insert0成功提交,courseService.insertCourse()被回滚了
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){

        try {
            courseService.insertCourse();
        } catch (Exception e) {
            e.printStackTrace();
        }

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);


    }

}



@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.NESTED)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

    }
}

B方法都用@Transactional(propagation = Propagation.REQUIRES_NEW)来修饰,是否也能达到这个效果呢?


@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private CourseService courseService;




    @Transactional(propagation = Propagation.REQUIRED)
    public void insert0(){

        try {
            //由于这个方法使用了@Transactional(propagation = Propagation.REQUIRES_NEW)
            //尽管内部抛出异常,但是,insert0()方法的事务不会被影响
            courseService.insertCourse();
        } catch (Exception e) {
            e.printStackTrace();
        }

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);


    }

}



@Service
public class CourseService {

    @Autowired
    private CourseMapper courseMapper;


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void insertCourse(){
        Course course = new Course();
        course.setId(1);
        course.setName("course_"+  System.currentTimeMillis());
        courseMapper.insert(course);

        int i = 1/0;
    }
}

2.8、无事务运行


@Service
public class StudentService {


    @Autowired
    private StudentMapper studentMapper;



    //没有使用@Transactional注解,以无事务方式运行
    //studentMapper.insert(student);自动提交,不会被回滚
    public void insert0(){

        Student student = new Student();
        student.setId(1);
        student.setName("student_"+ System.currentTimeMillis());
        studentMapper.insert(student);

        int i = 1/0;//这里抛出异常,但是studentMapper.insert会自动提交,不会被回滚


    }

}

3、事务失效情况

3.1、使用了@Transactional的方法,被同一个类里面的无@Transactional方法调用,@Transactional的方法无效。

下面的这种情况,student表 和 source表 都能成功添加数据,回滚失败。注意:这是在同一个类中的方法相互调用,上述的是不同类的方法调用,上下文不违背!

@Service
public class StudentImpl implements IStudent {

    @Autowired
    public StudentMapper studentMapper;

    @Autowired
    public SourceMapper sourceMapper;

    @Autowired
    public ISource source;

	@Override
    public void insert0() {
        Student student = new Student();
        student.setId(1);
        student.setName("student:123-sad");
        studentMapper.insert(student);
        
        insertProxy();
    }

    @Transactional
    public void insertProxy(){
        Source source = new Source();
        source.setId(210);
        source.setName("source:210=qqwe");
        sourceMapper.insert(source);
        
        int i = 1/0;
    }

但是下面这种情况B方法是可以回滚成功的,但A方法不能回滚,与第二章说明的情况一致

@Service
public class StudentImpl implements IStudent {

    @Autowired
    public StudentMapper studentMapper;

    @Autowired
    public SourceMapper sourceMapper;

    @Autowired
    public ISource source;

	@Override
    public void insert0() {
        Student student = new Student();
        student.setId(1);
        student.setName("student:123-sad");
        studentMapper.insert(student);
        
        insertProxy();
    }

	//无论这里有没有@Transactional注解,source.insert0()一样能回滚成功
    @Transactional	
    public void insertProxy(){
		source.insert0();
    }
    

    
@Service
public class SourceImpl implements ISource {

    @Autowired
    public SourceMapper sourceMapper;

    @Override
    @Transactional
    public void insert0() {
        Source source = new Source();
        source.setId(210);
        source.setName("source:210=qqwe");
        sourceMapper.insert(source);

        int i = 1/0;

    }
}

原因:Spring的事务管理是基于动态代理对象的代理逻辑实现的,那么如果在类内部的非事务方法调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,绕过的代理对象,肯定就是没有代理逻辑了。可以理解为使用了Spring注入的bean才会生成动态代理对象,更详细解释请看这里 https://blog.csdn.net/qq_45228323/article/details/125168679

解决方法:使用在类中注入自己的bean,加上@Lazy是为了防止bean的循环依赖注入。但是在实际开发中很少这样写,但这样确实能解决@Transactional失效的问题

@Service
public class StudentImpl implements IStudent {

    @Autowired
    public StudentMapper studentMapper;

    @Autowired
    public SourceMapper sourceMapper;

    @Autowired
    public ISource source;

    @Autowired
    @Lazy
    public StudentImpl studentImpl;

    @Override
    public void insert0() {

        Student student = new Student();
        student.setId(1);
        student.setName("student:123-sad");
        studentMapper.insert(student);

        studentImpl.insertProxy();
    }

	//insertProxy()方法能成功回滚,Source表没有数据,但insert0()还是会添加成功,Student表有数据
    @Transactional
    public void insertProxy(){
        Source source1 = new Source();
        source1.setId(999);
        source1.setName("source:999=qqwe");
        sourceMapper.insert(source1);

        int i = 1/0;
    }
}

区分:下面这种情况是 绝对能回滚 的,insertProxy()方法只是对代码的抽取而已,请不要搞混。

@Service
public class StudentImpl implements IStudent {

    @Autowired
    public StudentMapper studentMapper;

    @Autowired
    public SourceMapper sourceMapper;

    @Autowired
    public ISource source;

	@Override
	@Transactional
    public void insert0() {
        Student student = new Student();
        student.setId(1);
        student.setName("student:123-sad");
        studentMapper.insert(student);
        
        insertProxy();
    }
    
    private void insertProxy(){
        Source source = new Source();
        source.setId(210);
        source.setName("source:210=qqwe");
        sourceMapper.insert(source);
        
        int i = 1/0;
    }

4. 奇特的回滚方式

我们都知道,在Service层打上@Transactional后,若在该层操作出错了,不捕获异常,交由Controller层去捕获,则会回滚;但是如果异常在Service层就被捕获了,则不会回滚。
但有以下方式,即使在Service层捕获了异常,仍然可以回滚成功。

@RestController
public class InsertController {

    @Autowired
    public IStudent studentService;

    @GetMapping("/insert")
    public String insert(){
        String result = "error";
        try {
            result = studentService.insert0();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

@Service
public class StudentImpl implements IStudent {
    @Autowired
    public ISource sourceService;

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public String insert0() throws Exception {
        String result = sourceService.insert0();
        if ("fail".equals(result)) {
            throw new Exception();
        }
        return "OK";
    }
}


@Service
public class SourceImpl implements ISource {

    @Autowired
    public SourceMapper sourceMapper;

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public String insert0() throws Exception{
        String result = "success";
        try {
            Source source = new Source();
            source.setName("source:210=qqwe");
            sourceMapper.insert(source);

            int i = 1/0;
        }catch (Exception e){
            result = "fail";
        }
        return result;
    }
}

这是因为A方法调用了B方法,A方法和B方法组成了一个事务,虽然B方法异常确实是被捕获到了,但是抛出异常的是A方法,由于A方法和B方法已经组成了一个事务了,所以这两个方法会一起回滚!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值