Spring源码阅读(十二)—事务

Spring源码阅读(十二)—事务

事务是指多个数据库操作组成的整体,只有全部操作执行成功整体才成功,一旦有操作实行失败整体回滚到开始的状态;

事务的四大特性:原子性,一致性,隔离性,持久性

事务的四种隔离级别:未提交读,提交读,可重复读,可串行化

事务的七种传播行为:propagation_required,propagation_supports,propagation_mandatory,propagation_requires_new,propagation_not_supported,propagation_never,propagation_nested;

个人主页:tuzhenyu’s page
原文地址:Spring源码阅读(十二)—事务

Spring通过事务传播特性控制方法嵌套时,当前事务如果传播到嵌套调用的目标方法中;

(0) Spring事务的使用

  • Spring对事务的管理主要分为编程式事务管理和声明式事务管理

  • 编程式事务管理主要是通过TransactionTemplate类和TransactionCallback类实现

public class UserService{

    @Autowired

    private UserDao userDao;

    @Autowired

    private TransactionTemplate template;



    public void addUser(User user){

        template.execute(new TransactionCallback(){

            @Override   

            protected void doIntransaction(TransactionStatus status){

                    userDao.addUser(user);

            }

        });

    }

}
  • 声明式事务主要包括XML配置方式和注解配置方式

    • 声明式事务主要是通过Spring AOP实现,通过XML或者注解中声明的信息,Spring通过AOP将事务增强逻辑动态地织入业务方法的相应连接点中,这些逻辑中包括事务的开始,提交,混滚等

    • Spring与事务管理有关的接口主要包括:TransactionDefinition,PlatformTransactionManager,TransactionStatus;

      • TransactionDefinition主要负责声明中关于事务相关信息的存储,如事务的隔离级别,事务的传播特性,事务的只读状态等;

      • TransactionStatus代表了一个事务的具体运行状态,事务管理器可以通过该接口的方法获取事务运行期的状态信息

      • PlatformTransactionManager事务管理类,包含commit()和rollback()等事务管理方法

    • 通过解析XML配置文件和注解获取事务定义TransactionDefinition,通过TransactionDefinition获取TransactionStatus,通过TransactionStatus简洁执行事务相关的操作;

public interface PlatformTransactionManager{

    TransactionStatus getTransaction(TransactionDefinition definition);

    void commit(TransactionStatus status);

    void rollback(TransactionStatus status);

}
  • Spring事务管理实例

    • 配置数据源DateSource,并将数据源注入DataSourceTransactionManager事务管理类和JdbcTemplate模板类中

    • 通过开启注解声明式事务

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="transaction"/>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="balbal"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"  ref="dataSource" />
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource"  ref="dataSource" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

默认情况下Spring中的事务处理只对RuntimeException方法回滚,普通Exception不会让事务回滚;

@Service
public class UserService {
    @Autowired
    private JdbcTemplate template;

    @Transactional
    public void save(User user){
        template.update("insert into user(name,password,score) values(\""+user.getName()+
                "\",\""+user.getPassword()+"\",\""+user.getScore()+"\")");
        throw new RuntimeException("AA");    
    }
}
public class Main {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService)applicationContext.getBean("userService");
        User user = new User();
        user.setName("bala");
        user.setPassword("121212");
        user.setScore("88");
        userService.save(user);
    }
}

(1) Spring事务的源码分析

注册自动代理生成器

  • Spring启动时候会根据XML配置文件初始化容器ApplicationContext,在解析配置文件时候如果相应标签是自定义标签则会调用相应特定的解析器进行处理;
<tx:annotation-driven transaction-manager="transactionManager"/>

annotation-driven是tx命名空间下的自定义标签,找到其特定的解析器

public void init() {
    this.registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
    this.registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
    this.registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
  • 如果配置mode=”aspectj”则会使用AspectJ的方式听过静态代理的方式进行织入事务管理逻辑;默认采用动态代理的形式创建事务;
public BeanDefinition parse(Element element, ParserContext parserContext) {
    String mode = element.getAttribute("mode");
    if("aspectj".equals(mode)) {
        this.registerTransactionAspect(element, parserContext);
    } else {
        AnnotationDrivenBeanDefinitionParser.AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
    }

    return null;
}
  • 注册自动代理创建器autoProxyCreator

    • 调用registerAutoProxyCreator()方法注册infrastructureAdvisorAutoProxyCreator自动代理创建器,该类实现了beanPostProcessor接口,如果被注册,在getBean()获取bean实例时会调用其postProcessAfterInitialization()方法;

    • 创建BeanFactoryTransactionAttributeSourceAdvior切面类的bean实例

    • 创建TransactionInterceptor事务代理逻辑类的bean实例

    • 创建AnnotationTransactionAttributeSource类实例

    • 将TransactionInterceptor实例bean和AnnotationTransactionAttributeSource实例bean注入到BeanFactoryTransactionAttributeSourceAdvior切面类的实例bean中;

public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
    AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
    String txAdvisorBeanName = "org.springframework.transaction.config.internalTransactionAdvisor";
    if(!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
        Object eleSource = parserContext.extractSource(element);
        RootBeanDefinition sourceDef = new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
        sourceDef.setSource(eleSource);
        sourceDef.setRole(2);
        String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
        RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
        interceptorDef.setSource(eleSource);
        interceptorDef.setRole(2);
        AnnotationDrivenBeanDefinitionParser.registerTransactionManager(element, interceptorDef);
        interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
        String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
        RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
        advisorDef.setSource(eleSource);
        advisorDef.setRole(2);
        advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
        advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
        if(element.hasAttribute("order")) {
            advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
        }

        parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
        CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
        compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
        compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
        compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
        parserContext.registerComponent(compositeDef);
    }

}

代理实现的入口

  • spring 容器启动,在每个bean实例话过程中会首先尝试到缓存中获取,获取上失败后会调用createBean()方法从头创建bean.在调用doCreateBean()方法正式创建之前会调用resolveBeforeInstantiation()方法尝试是否创建代理类替代真正的实例,如果创建成功则直接返回跳过后续的真正创建过程,如果创建失败则继续创建bean实例.
Object beanInstance;
try {
    beanInstance = this.resolveBeforeInstantiation(beanName, mbd);
    if(beanInstance != null) {
        return beanInstance;
    }
} catch (Throwable var6) {
    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var6);
}
  • 在resolveBeforeInstantiation()方法中会调用提前注册的处理器AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization()方法实现代理的创建
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if(!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        if(!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
            Class targetType = this.determineTargetType(beanName, mbd, new Class[0]);
            if(targetType != null) {
                bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if(bean != null) {
                    bean = this.applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }

        mbd.beforeInstantiationResolved = Boolean.valueOf(bean != null);
    }

    return bean;
}
  • postProcessAfterInitialization()方法调用wrapIfNecessary()方法进行代理的实现
public Object <strong>postProcessAfterInitialization</strong>(Object bean, String beanName) throws BeansException {

        if (bean != null) {

            Object cacheKey = getCacheKey(bean.getClass(), beanName);

            if (!this.earlyProxyReferences.containsKey(cacheKey)) {

                return wrapIfNecessary(bean, beanName, cacheKey);

            }

        }

        return bean;

    }
  • wrapIfNecessary()方法实现了aop实现的主要逻辑,调用getAdvicesAndAdvisorsForBean()提取当前bean 的所有增强方法,然后调用createProxy()方法创建具体代理.
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {

        if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) {

            return bean;

        }

        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {

            return bean;

        }

        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {

            this.advisedBeans.put(cacheKey, Boolean.FALSE);

            return bean;

        }

        Object[] specificInterceptors = <strong>getAdvicesAndAdvisorsForBean</strong>(bean.getClass(), beanName, null);

        if (specificInterceptors != DO_NOT_PROXY) {

            this.advisedBeans.put(cacheKey, Boolean.TRUE);

            Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

            this.proxyTypes.put(cacheKey, proxy.getClass());

            return proxy;

        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);

        return bean;

    }    
增强的获取
  • getAdvicesAndAdvisorsForBean()主要是通过调用findEligibleAdvisors()方法用来获取该bean的增强列表.主要步骤包括:

    • 寻找所有增强

    • 从所有增强中获取适合该bean的增强.

protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {

    List<Advisor> candidateAdvisors = findCandidateAdvisors();

    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

    extendAdvisors(eligibleAdvisors);

    if (!eligibleAdvisors.isEmpty()) {

        eligibleAdvisors = sortAdvisors(eligibleAdvisors);

    }

    return eligibleAdvisors;

}
  • findCandidateAdvisors()方法是用来获取所有的增强,主要步骤包括:

    • 获取所有在beanFactory中注册的beanName

    • 遍历所有的beanName,判断是否为声明为AspectJ的类,如果是则进行进一步处理

    • 对标记为AspectJ注解的类判断是不是Advisor增强类,如果是则将其放入缓存

在注册自动代理创建器时,创建了一个BeanFactoryTransactionAttributeSourceAdvisor类实例bean,并放入容器中;在获取所有增强时会将此bean提取出来;

protected List<Advisor> findCandidateAdvisors() {
    List advisors = super.findCandidateAdvisors();
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    return advisors;
}
  • 调用findAdvisorsThatCanApply()方法从所有增强中获取适合该bean的增强
protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);

    List var4;
    try {
        var4 = AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    } finally {
        ProxyCreationContext.setCurrentProxiedBeanName((String)null);
    }

    return var4;
}
  • 在从所有增强中获取适合该bean的增强时候会提取事务标签,用来判断是否适用事务增强;

    • 如果方法上存在事务属性配置,则使用方法上的事务属性;如果方法上没有则使用类上的;如果类上没有则搜索实现接口方法上,再搜索实现接口上的事务属性;
  • 如果事务增强器BeanFactoryTransactionAttributeSourceAdvisor适用当前类,则会根据事务属性和注入的TransactionIntercepter生成相应的代理类;

  • TransactionInterceptor类型的bean被注入到了BeanTransactionAttributeSourceAdvisor中,所以,在调用事务增强器增强的代理类时会首先执行TransactionInterceptor进行增强,同时,也就是在TransactionInterceptor类中的invoke方法中完成整个事务的逻辑

public Object invoke(final MethodInvocation invocation) throws Throwable {
    Class targetClass = invocation.getThis() != null?AopUtils.getTargetClass(invocation.getThis()):null;
    return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
        public Object proceedWithInvocation() throws Throwable {
            return invocation.proceed();
        }
    });
}
  • invoke()方法调用invokeWithinTransaction()方法实现具体的事务逻辑
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
    final TransactionAttribute txAttr = this.getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
    final PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
    final String joinpointIdentification = this.methodIdentification(method, targetClass);
    if(txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
        try {
            Object ex1 = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, new TransactionCallback() {
                public Object doInTransaction(TransactionStatus status) {
                    TransactionAspectSupport.TransactionInfo txInfo = TransactionAspectSupport.this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

                    TransactionAspectSupport.ThrowableHolder var4;
                    try {
                        Object ex = invocation.proceedWithInvocation();
                        return ex;
                    } catch (Throwable var8) {
                        if(txAttr.rollbackOn(var8)) {
                            if(var8 instanceof RuntimeException) {
                                throw (RuntimeException)var8;
                            }

                            throw new TransactionAspectSupport.ThrowableHolderException(var8);
                        }

                        var4 = new TransactionAspectSupport.ThrowableHolder(var8);
                    } finally {
                        TransactionAspectSupport.this.cleanupTransactionInfo(txInfo);
                    }

                    return var4;
                }
            });
            if(ex1 instanceof TransactionAspectSupport.ThrowableHolder) {
                throw ((TransactionAspectSupport.ThrowableHolder)ex1).getThrowable();
            } else {
                return ex1;
            }
        } catch (TransactionAspectSupport.ThrowableHolderException var14) {
            throw var14.getCause();
        }
    } else {
        TransactionAspectSupport.TransactionInfo ex = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
        Object retVal = null;

        try {
            retVal = invocation.proceedWithInvocation();
        } catch (Throwable var15) {
            this.completeTransactionAfterThrowing(ex, var15);
            throw var15;
        } finally {
            this.cleanupTransactionInfo(ex);
        }

        this.commitTransactionAfterReturning(ex);
        return retVal;
    }
}
  • 在createTransactionIfNecessary()方法通过调用getTransaction()方法创建事务Transaction;
protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm, final TransactionAttribute txAttr, final String joinpointIdentification) {
    if(txAttr != null && ((TransactionAttribute)txAttr).getName() == null) {
        txAttr = new DelegatingTransactionAttribute((TransactionAttribute)txAttr) {
            public String getName() {
                return joinpointIdentification;
            }
        };
    }

    TransactionStatus status = null;
    if(txAttr != null) {
        if(tm != null) {
            status = tm.getTransaction((TransactionDefinition)txAttr);
        } else if(this.logger.isDebugEnabled()) {
            this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");
        }
    }

    return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);
}
    public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {

        Object transaction = doGetTransaction();    //获取事务实例



        // Cache debug flag to avoid repeated checks.

        boolean debugEnabled = logger.isDebugEnabled();



        if (definition == null) {

            // Use defaults if no transaction definition given.

            definition = new DefaultTransactionDefinition();

        }



        if (isExistingTransaction(transaction)) {                                                                // 内嵌事务处理,先不关注

            // Existing transaction found -> check propagation behavior to find out how to behave.

            return handleExistingTransaction(definition, transaction, debugEnabled);

        }



        // Check definition settings for new transaction.

        if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {                                    // 超时设置

            throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());

        }



        // No existing transaction found -> check propagation behavior to find out how to proceed.

        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {

            throw new IllegalTransactionStateException(

                    "No existing transaction found for transaction marked with propagation 'mandatory'");

        }

        else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||

                definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||

            definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

            SuspendedResourcesHolder suspendedResources = suspend(null);

            if (debugEnabled) {

                logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);

            }

            try {

                boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

                DefaultTransactionStatus status = newTransactionStatus(

                        definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

                // 构建transaction,包括ConnectionHolder、隔离级别、timeout,如果是新连接,绑定到当前线程,这是我们需要关注的点

                doBegin(transaction, definition);                                                        

                prepareSynchronization(status, definition);

                return status;

            }

            catch (RuntimeException ex) {

                resume(null, suspendedResources);

                throw ex;

            }

            catch (Error err) {

                resume(null, suspendedResources);

                throw err;

            }

        }

        else {

            // Create "empty" transaction: no actual transaction, but potentially synchronization.

            boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

            return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);

        }

    }
  • 在getTransaction()方法中通过doBegin()方法获取数据连接connection
    @Override

    protected void doBegin(Object transaction, TransactionDefinition definition) {

        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

        Connection con = null;



        try {

            // 尝试获取连接

            if (txObject.getConnectionHolder() == null ||                                                

                    txObject.getConnectionHolder().isSynchronizedWithTransaction()) {

                Connection newCon = this.dataSource.getConnection();

                if (logger.isDebugEnabled()) {

                    logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");

                }

                txObject.setConnectionHolder(new ConnectionHolder(newCon), true);

            }
      txObject.getConnectionHolder().setSynchronizedWithTransaction(true);

            con = txObject.getConnectionHolder().getConnection();
            // 设置隔离级别

            Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);

            txObject.setPreviousIsolationLevel(previousIsolationLevel);



            // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,

            // so we don't want to do it unnecessarily (for example if we've explicitly

            // configured the connection pool to set it already).

            // 更改自动提交设置,有spring控制提交

            if (con.getAutoCommit()) {

                txObject.setMustRestoreAutoCommit(true);

                if (logger.isDebugEnabled()) {

                    logger.debug("Switching JDBC Connection [" + con + "] to manual commit");

                }

                con.setAutoCommit(false);

            }

            // 设置当前线程是否存在事务的依据

            txObject.getConnectionHolder().setTransactionActive(true);

            int timeout = determineTimeout(definition);

            if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {

                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);

            }

            // Bind the session holder to the thread.

            if (txObject.isNewConnectionHolder()) {

                // 将当前获取到的连接绑定到当前线程

                TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());

            }

        }

        catch (Throwable ex) {

            if (txObject.isNewConnectionHolder()) {

                DataSourceUtils.releaseConnection(con, this.dataSource);

                txObject.setConnectionHolder(null, false);

            }

            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);

        }

    }
  • 事务会在代理类中将数据库连接与线程绑定,保证事务的操作是在同一个线程下;在同一个connection进行具体的事务操作如事务提交,回滚等;

结论

  • 事务标签的解析,注册事务相关的类到容器中,代理类以及事务功能的三个bean:BeanFactoryTransactionAttributeSourceAdvisor、AnnotationTransactionAttributeSource、TransactionInterceptor

  • 找出指定bean对应的增强器,具体一点,就是如果类方法或者类带有注解@Transaction则适用增强器BeanFactoryTransactionAttributeSourceAdvisor;

  • 根据类和适用的增强创建代理类,创建的代理类将增强方法与目标方法集合生成增强后的方法,在方法的增强中有一个很重要的操作:在执行JdbcTemplate操作之前将connection绑定到当前线程,也就是说在事务开启时会从数据库连接池中获取connection,将其与当前线程绑定;

  • Spring封装的jdbc操作JdbcTemplate,在执行具体SQL时会先判断当前线程是否有connection(connHolder),有则直接返回,那么就保证了目标方法中的所有数据库操作用的是同一个connection,事务操作的也是同一个connection;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值