SQL事务实现方式:编程式与声明式

Arm MPAM内存带宽监控寄存器详解与应用 内存带宽监控是现代计算机体系结构中的关键技术,通过硬件寄存器实现对内存访问的精确测量。Arm架构的MPAM扩展提供了完整的监控机制,其中MSMON_MBWU_L_CAPTURE寄存器为核心组件,支持多安全域隔离和资源实例选择。该寄存器包含状态标志位和带宽计数器,可配置不同位宽以适应从常规服务器到高性能计算的各种场景。在云计算和可信执行环境(TEE)中,这种监控机制尤为重要,既能确保资源隔离,又能提供精确的性能数据。通过合理配置过滤机制和中断处理,可以显著降低监控开销,适用于数据库优化、AI训练等内存密集型应 阅读详情

SQL事务实现简介

​ 首先我们来了解下,最简单的事务是怎么实现的呢?以JDBC为例,当一个数据库Connection对象创建后,其会默认自动提交事务;每次执行SQL语句时,如果成功,就会向数据库自动提交,不能回滚。

​ 通过调用setAutoCommit(false)方法可以取消自动提交事务。等到所有的SQL语句都执行成功后,调用commit()方法提交事务。如果其中某个操作失败或出现异常时,则调用rollback()方法回滚事务。具体代码如下所示:

public void noTransaction() { Connection connection = null; String sql = "update account set balance=balance-100 where id=1"; String sql2 = "update account set balance=balance+100 where id=2"; //创建PreparedStatement对象 PreparedStatement preparedStatement = null; try { connection = JDBCUtils.getConnection();// 获取数据库连接 connection.setAutoCommit(false);//事务开始 preparedStatement = connection.prepareStatement(sql); preparedStatement.executeUpdate();//执行第一个sql preparedStatement = connection.prepareStatement(sql2); preparedStatement.executeUpdate();//执行sql2 //提交事务 connection.commit(); } catch (SQLException e) { //进行事务回滚,默认回滚到事务开始的地方 try { connection.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); } finally { //关闭流 JDBCUtils.close(null, preparedStatement, connection); } } 复制代码

​ 将代码抽象成执行步骤,主要有以下四步:

  1. 获取Mysql链接

  2. 执行SQL语句

  3. 提交SQL事务

  4. 存在异常则做Mysql的事务回滚。

​ 可以发现,常规情况下只有执行SQL语句的内容存在差异。如果能将相同部分抽取出来,接入方接入时只考虑SQL语句内容,就可以减少接入的成本。同时观察到抽取的部分处于执行SQL语句的前后,那么很自然的就可以想到两种解决方案:

​ 1、在JAVA8中,提供了函数式编程。我们可以将要执行的SQL语句封装成函数,作为入参传入并执行。

​ 2、采用动态代理对执行SQL的前后做增强。

编程式事务

​ Spring中采用函数式编程实现的事务,被称为编程式事务。编程式事务的实现相对简单,主要由类TransactionTemplate负责实现。具体代码可以见如下所示:

@Override @Nullable public <T> T execute(TransactionCallback<T> action) throws TransactionException { Assert.state(this.transactionManager != null, "No PlatformTransactionManager set"); if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); } else { //获取事务 TransactionStatus status = this.transactionManager.getTransaction(this); T result; try { //执行SQL语句内容 result = action.doInTransaction(status); } catch (RuntimeException | Error ex) { //异常回滚 rollbackOnException(status, ex); throw ex; } catch (Throwable ex) { // 异常回滚 rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } //提交事务 this.transactionManager.commit(status); return result; } } 复制代码

​ TransactionCallBack作为入参传入,其中就主要是我们要执行的SQL语句内容。而其余部分可以看到,其实就和我们前面所描述的四步基本相似:

  1. 获取Mysql链接

  2. 执行SQL语句

  3. 提交SQL事务

  4. 存在异常则做Mysql的事务回滚。

声明式事务

​ 在Spring中,采用AOP做增强逻辑的被称为声明式事务。相比起编程式事务,声明式事务相对复杂。因此,在了解声明式事务之前,我们需要先简单了解一下Spring是如何支持AOP(动态代理)。首先我们知道,Spring中Bean的存在形式有以下几个阶段:

​​ 其中非常关键点就在BeanFactory。当我们对一个Bean定义代理对象后,BeanFactory生成的就不会是单纯的Bean实例对象,而是Bean的动态代理。通过调用Bean的动态代理中的方法,来实现AOP。那么如何自定义自己的AOP呢?要实现AOP需要明确两个点:

1、需要在哪里做增强?(定义切点)

2、需要做什么样的增强逻辑?(定义增强逻辑)

​ 对于这两点,Spring主要通过**事务代理管理配置类(ProxyTransactionManagementConfiguration)**进行实现。

​​ 从类图中可以看到,事务代理管理配置类主要定义了三个Bean对象:

  • 注释事务属性源(AnnotationTransactionAttributeSource),其主要负责判断当前类是否为需要增强的类,即"哪里需要做增强"。

  • 事务拦截器(TransactionInterceptor),该类主要负责对事务做链接获取、事务提交以及事务回滚。即"怎么做增强"。

  • Bean工厂事务属性源指导(BeanFactoryTransactionAttributeSourceAdvisor),这个与事务本身无关,主要是在Bean工厂生产Bean实例的时候,方便对Bean进行替换使用的。其中主要是负责将定义的切点和增强逻辑注入到Spring中。

这里我们逐一来介绍这三个Bean对象。

注释事务属性源

​ "哪里需要做增强",意味着类要具备判断是否需增强的能力。为此,注释事务属性源提供了一个关键的方法:isCandidateClass()。

​ 但声明事务的注解一定不只一种。如果需要识别所有包下的事务型注解,一定会需要多次判断。因此,在注解事务属性源中,还保存了一组接口对象事务注释解析器(TransactionAnnotationParser),通过循环遍历这组事务注释解析器,就可以对不同框架注解进行处理。具体源码如下:

@Override public boolean isCandidateClass(Class<?> targetClass) { for (TransactionAnnotationParser parser : this.annotationParsers) { if (parser.isCandidateClass(targetClass)) { return true; } } return false; } 复制代码

​ 以SpringTransactionAnnotationParser注释解析器为例,其实现的isCandidateClass()方法判断类是否被@Transactional类注释了,如果是,那么该类就是潜在的候选类。

@Override public boolean isCandidateClass(Class<?> targetClass) { return AnnotationUtils.isCandidateClass(targetClass, Transactional.class); } 复制代码

​ 依次类推,对@TransactionAttribute等其他框架的注释,我们都可以采用这样方法实现。

事务拦截器

​ 具备了判断哪些类需要执行事务的能力后,我们还需要确定具体的增强逻辑是什么样子的。而这就是事务拦截器主要功能。要实现这个功能,需要在对应方法被调用时,执行增强方法。

​​ 从类图首先可以看到,为了能够察觉到方法的调用,事务拦截器实现了方法拦截器接口(MethodInterceptor)的invoke方法,在invoke方法中先判断当前执行的方法属于哪个类,紧接着会用invokeWithinTransaction()对方法进行事务性的包装。其源码如下:

@Override @Nullable public Object invoke(MethodInvocation invocation) throws Throwable { // 判断执行的方法属于哪个类 Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); //再调用事务进行执行 return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() { @Override @Nullable public Object proceedWithInvocation() throws Throwable { return invocation.proceed(); } @Override public Object getTarget() { return invocation.getThis(); } @Override public Object[] getArguments() { return invocation.getArguments(); } }); } 复制代码

​ 主要逻辑放在invokeWithinTransaction()方法中。在该方法中,主要考虑了三类不同的编程方式的事务,分别是:响应式事务(ReactiveTransactionManager)、回调优先型事务(CallbackPreferringPlatformTransactionManager)和非回调优先型事务(非CallbackPreferringPlatformTransactionManager)。

三者的差异主要在于:

1、响应式编程常采用Mono或Flux实现,需要对两种方式选择相应适配器做适配。

2、后两者从名字上可以看出差异,回调型优先的事务,会先执行回调再执行事务。而非回调优先型事务,则关注于事务的执行,至于回调的失败与否不需要影响事务的回滚。

尽管三者存在一些差异,但他们对于事务的实现其实是相似的,这里以非回调优先型事务为例子:

@Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { TransactionAttributeSource tas = getTransactionAttributeSource(); final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); final TransactionManager tm = determineTransactionManager(txAttr); ....... PlatformTransactionManager ptm = asPlatformTransactionManager(tm); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) { // 创建事务 TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); Object retVal; try { // 执行方法 retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // 回滚处理 + 抛出异常终止执行 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } // 正常执行了事务,此时再执行回调 if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) { TransactionStatus status = txInfo.getTransactionStatus(); if (status != null && txAttr != null) { retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); } } // 提交事务 commitTransactionAfterReturning(txInfo); return retVal; } } 复制代码

​ 源码本身不复杂,可以看到也是四步:

  1. 获取Mysql链接信息

  2. 执行SQL语句

  3. 提交SQL事务

  4. 存在异常则做Mysql的事务回滚。

Bean工厂事务属性源指导

​ 对于Bean工厂事务属性源指导,其主要负责用于定义切点和增强逻辑,并将这些事务的逻辑注册到Spring中用于实现。如下是Bean工厂事务属性源指导的类图。

​​ 从类图上可以看到,其继承了AbstractPointcutAdvisor关键模版类,该类是Spring中用于定义切点和增强逻辑。通过指定PointCut和Advice,就可以实现自定义的增强逻辑。因此,Bean工厂事务属性源指导只要将事务拦截器标记为增强逻辑,将注释事务属性源标记为切点,就可以让其在Spring中作为AOP生效。

​ 通过这三者的合作:注释事务属性源标注了切点(说明我那些方法需要做增强);事务拦截器定义了要执行的增强逻辑(说明我对这些方法怎么做增强);Bean工厂事务属性源指导则将切点和增强逻辑注入到Spring中使其生效。从而实现了Spring的声明式事务的内容。

事务多样性支持

​ 在前述内容中,我们思考了SQL情况下如何实现事务。但有个问题,如果数据源换成Redission、换成分布式事务的API,代码还能快速复用么?简而言之,Spring是如何支持数据源多样性?如何确保新数据源的快速接入?

​ 对实现事务的流程做进一步抽象,不难发现一次事务中,框架需要关注的功能其实只有三个:

  1. 获取事务链接

  2. 提交事务

  3. 事务回滚

​ 因此,对不同的数据源,都可以将其抽象成这三个能力。应用层只需要对这三个能力进行调用,就不会在因为下层数据源的差异而需要大幅度的改动。而这正与面向接口设计的思想不谋而合

​​ 为此,Spring专门设计了接口PlatformTransactionManager,其主要负责对外提供三个方法:getTransaction(definition)、commit(status)、rollback(status)。就用来抽象的上述的三个功能。由此一来,应用层的代码实现类(这里以TransactionTemplate为例子)就不再需要依赖于我的数据源究竟是JDBC、Redission还是DataSource。面对抽象编程,从而减少了接入需要考虑不同类型所带来的成本。

总结

​ 本文介绍了Spring中针对SQL事务实现的两种方式:编程式事务和声明式事务。同时介绍了对于多种不同的数据源,Spring在设计上的架构实现,希望对大家后续的开发设计有所帮助。

Javaweb/SSM原理与实战 Spring是什么Spring是分层的JavaSE/EE应用全栈轻量级开源框架,以IOC(Inverse Of Control 控制反战)和AOP(Aspect Oriented Programming 面向切面编程)为内核。提供了展现层SpringMVC和持久层SpringJDBCTemplate以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的JavaEE企业应用开源框架。Spring的优势方便解耦,简化开发。 阅读详情

相关推荐

【Out-of-Distribution Detection】Evidential Deep Learning in NeurIPS 2018 个人理解

核心思想是将分类器的概率输出视为一个狄利克雷分布(Dirichlet Distribution)并替换,之后引入两个损失分别负责保证预测结果准确性和提升被错误分类的样本的不确定性。

研究兴趣:开放集识别、开放世界识别、新类发现、增量学习、少样本学习 2432

浅析Spring事务实现原理

​ 首先我们来了解下,最简单的事务是怎么实现的呢?以JDBC为例,当一个数据库Connection对象创建后,其会默认自动提交事务;每次执行SQL语句时,如果成功,就会向数据库自动提交,不能回滚。​ 通过调用setAutoCommit(false)方法可以取消自动提交事务。等到所有的SQL语句都执行成功后,调用commit()方法提交事务。如果其中某个操作失败或出现异常时,则调用rollback()方法回滚事务。

Laugh_xiaoao的博客 790

CLIP-Count代码配置以及踩坑记录

CLIP-Count代码配置以及踩坑记录

学术菜鸡 1011

Spring事务的实现原理

Spring事务的实现原理

m0_54117624的博客 1万+

GStreamer 源代码入门

GStreamer 是一个高度模块化的多媒体框架,其源代码结构清晰,设计精良。

深之JohnChen的专栏 951

UWB 多传感器通信的纳秒无线位置和时钟同步方法

利用UWB高精度的特点,实现多节点下的无线时钟同步和定位。通过优化硬件架构,减少不确定延迟的影响,系统可以提供纳秒级时钟同步消息

DT程序员的博客 1324

【Spring框架】Spring事务的原理

本文将详细讲解Spring事务管理地底层原理,让你彻底搞懂Spring事务的运行机制。

小七的博客 3294

基于 PID 算法的 STM32 步进电机高精度位置控制系统设计与实现(工业自动化应用)

硬件层面:选用 STM32F103C8T6+A4988 + 欧姆龙编码器的组合,兼顾工业可靠性与成本,接线需注意强弱电分离和信号抗干扰;软件层面:核心为位置式 PID 闭环控制,Mermaid 流程图清晰展现 “采集 - 运算 - 驱动” 的闭环逻辑,代码模块化易移植;性能层面:无负载定位误差≤±1 脉冲,带载误差≤±3 脉冲,满足工业自动化高精度位置控制需求。

weixin_42300449的博客 193

事物java例子_spring事务详解(二)实例

在Spring中,事务有两种实现方式:编程式事务管理: 编程式事务管理使用底层源码可实现更细粒度的事务控制。spring推荐使用TransactionTemplate,典型的模板模式。申明式事务管理: 添加@Transactional注解,并定义传播机制+回滚策略。基于Spring AOP实现,本质是对方法前后进行拦截,方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚...

weixin_42523326的博客 228

使用Mask2Former和X-Decoder训练自定义数据集及结果复现报告

本报告记录了使用MMDetection框架中的Mask2Former和X-Decoder模型在自定义数据集上的训练过程。报告包含环境配置、数据集准备、模型训练与优化(解决了Mask2Former的PQ值异常问题)、性能评估等关键环节。详细展示了从数据集转换(将客户提供的COCO格式数据适配MMDetection框架)、配置文件修改、到最终模型训练和评估的全流程。特别针对Mask2Former训练中的PQ值异常问题提供了解决方案,并对比了两种模型在自定义数据集上的表现。报告还包含完整的代码实现和技术细节。

huanghm88的专栏 1088

基于 高斯过程回归(Gaussian Process Regression, GPR) 的 时间序列区间预测 的 MATLAB 示例代码

基于 高斯过程回归(Gaussian Process Regression, GPR) 的 时间序列区间预测 的 MATLAB 示例代码

算法如诗的博客 153

Spring事务和事务传播机制

事务是⼀组操作的集合,是⼀个不可分割的操作. 事务会把所有的操作作为⼀个整体,⼀起向数据库提交或者是撤销操作请求.所以这组操作要么同时成 功,要么同时失败事务传播机制就是:多个事务⽅法存在调⽤关系时,事务是如何在这些⽅法间进⾏传播的. ⽐如有两个⽅法A,B都被 @Transactional 修饰, A⽅法调⽤B⽅法 A⽅法运⾏时,会开启⼀个事务.当A调⽤B时,B⽅法本⾝也有事务,此时B⽅法运⾏时,是加⼊A的事务,还 是创建⼀个新的事务呢?这个就涉及到了事务的传播机制.

2501_91206597的博客 634

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

对spring 对持久层的支持和数据库连接池的理解

1.spring对持久层的支持在于,得到数据库连接之后操作上的封装,将操作简化了。也就是说以后操作sql语句就用XXXTemplate(就是一个工具类)对象了。 2.数据库连接池的作用只在于得到数据库的连接,并对数据库的连接做管理,不涉及到得到连接后的操 所以,spring对持久层的支持的XXXTemplate类是属于spring包下的,是spring的支持。但是数据库连接池的获取连...

dengliao9491的博客 294

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

SSM面试题

声明式事务管理(Declarative Transaction Management): 基于AOP(Aspect-Oriented Programming)的方式,通过在配置文件或注解中声明事务的属性来实现事务管理。可以通过XML配置文件中的。注入式事务管理(Injection Transaction Management): 通过将事务管理器注入到需要事务管理的Bean中,在Bean中直接调用事务管理器的方法来控制事务的开始、提交或回滚。因此,同一个XML映射文件中的ID必须是唯一的,不允许重复。

weixin_60934893的博客 1552

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

JavaGuide面试突击版笔记(二)

Spring Spring 框架中⽤到了哪些设计模式 ⼯⼚设计模式 : Spring使⽤⼯⼚模式通过 BeanFactory 、 ApplicationContext 创建 bean 对象 代理设计模式 : Spring AOP 功能的实现 单例设计模式 : Spring 中的 Bean 默认都是单例的. 等等 Spring 管理事务的⽅式有⼏种 编程式事务,在代码中硬编码。(不推荐使⽤) 声明式事务,在配置⽂件中配置(推荐使⽤...

lijieling123的博客 250

MyBatis与Spring整合:核心配置与最佳实践

Mapper接口应简洁明了,只包含与数据库操作相关的接口方法,避免将业务逻辑混入其中。接口方法命名应遵循一定的规范,便于理解和维护。

MoneyHacksPro的博客 1098

SSM框架实训测试题整理2

MyBatis提供了两级缓存来提高查询性能。特性一级缓存二级缓存作用域SqlSession级别。级别。默认开启是。否,需要在配置文件中显式开启()并在Mapper.xml中配置<cache/>。共享性同一个SqlSession内共享。同一个namespace下的所有SqlSession共享。失效时机当执行操作,或调用,或关闭SqlSession时,一级缓存会清空。当执行同namespace下的增删改操作时,二级缓存会被清空。也可以通过配置设置刷新间隔等。存储结构内存中的一个简单HashMap。

Hz10220022的博客 807

Java面试:2021.05.13

1、什么是红黑树?哪里用到了? 红黑树是一种含有红黑结点并能自平衡的二叉查找树。它必须除了满足二叉搜索树的性质外,还要满足下面的性质: 性质1:每个节点要么是黑色,要么是红色。 性质2:根节点是黑色。 性质3:每个叶子节点(NIL)是黑色。 性质4:每个红色结点的两个子结点一定都是黑色。 性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。 应用: 1、java8 hashmap中链表转红黑树。 优势: 时间复杂度从O(n)-->O(logn) ,且自旋开销较其他树较低(不用整体平衡)。

一诺 314

同一个需求为何有多种写法?多一种范式,多一种解决问题的视角

编程范式决定了程序员组织代码与思考问题的底层方式。同一个需求,既可以用命令式循环实现,也可以用函数式流处理或声明式 SQL 表达,不同写法的背后是不同思维模型的映射。理解这些差异,不仅能够提升代码可读性与可维护性,也能帮助开发者在框架选择、事务管理、SQL 查询和配置文件等真实工程场景中做出更合理的决策。例如,Spring 的注解事务与编程式事务,MySQL 的 GROUP BY 与窗口函数,都体现了从控制流程到描述结果的思维切换。多掌握一种写法,不是追求代码炫技,而是为复杂业务多预留一个解决问题的角度,从

weixin_34391445的博客 472

Spring事务的几种实现方式

前言 1.、事务几种实现方式 (1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。 (2)基于 TransactionProxyFactoryBean的声明式事务管理 (3)基于 @Transactional 的声明式事务管理 (4)基于Aspectj...

mufeng 2万+

Spring 中声明式事务和编程式事务的使用

Spring 中的事务详解, 以及事务失效原因讲解. 快速入门 Spring 事务的使用

这个人很懒, 什么都没留下(这是我写的) 3243

事务概念(ACID、事务隔离级别)与Spring事务(编程式事务、声明式事务、事务传播方式、事务实现原理、事务失效解决)

一 事务 事务的特性 事务隔离级别 二 Spring事务 Spring 编程式事务 使用方式 Spring 声明式事务 使用方式 Spring中的事务隔离级别 Spring事务的传播方式 Spring 事务实现原理 Spring 事务注意的问题 事务失效问题 一、事务 事务是指 ...

wlin的博客 4041

spring事务实现的几种方式

spring事务处理 前言 1.、事务几种实现方式 (1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。 (2)基于 TransactionProxyFactoryBean的声明式事务管理 (3)基于 @Transactional 的声明式事务管理 (4)基于Aspectj AOP配置事务 编程式事务管理 第一:使用 TransactionTemplate 事务

weixin_41979002的博客 1万+

关于声明式事务和编程式事务使用详解

本文主要探讨了编程式事务和声明式事务两种事务管理方式。首先,介绍了编程式事务的概念,并深入解析了PlatformTransactionManager和TransactionTemplate这两个关键组件。然后,对声明式事务进行了概述,展示了其与编程式事务的不同之处。最后,总结了两种事务管理的优缺点,帮助读者更好地理解这两种方式在实际情况中的应用。

程序员Forlan的博客 763
上一篇: 这些13 种锁的实现方式你知道吗
下一篇: 聊聊什么是SpringBoot 的自动装配原理
Java_LingFeng
博客等级 码龄4年 505粉丝 259原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值