Java程序使用预处理语句的性能提升

什么是预处理?防SQL注入的原理?使用预处理防止被恶意注入 ⭐ 前言 ⭐本篇文章主要介绍什么是预处理?防sql注入的原理?使用预处理防止SQL被恶意注入简单知识以及部分理论知识 SQL注入是指攻击者通过在Web应用程序中注入恶意SQL代码,从而导致数据库执行恶意的SQL语句。为了防止SQL注入,可以采用以下原理: 在以上示例中,使用了 ' 任意值 ' or '1'='1' 的方法恶意注入了SQL语句,恶意用户输入 '任意值' or '1'='1',进行对SQL语句注入 从而影响最终结果。 阅读详情

Java程序使用预处理语句的性能提升

GreatSQL提供了对服务器端预处理语句(Prepared Statements)的支持。预处理语句可以利用了高效的客户机/服务器二进制协议。使用带有参数值占位符的预处理语句有以下好处:

  • 每次执行时解析语句的开销更少。通常,数据库应用程序处理大量几乎相同的语句,只对语句中的文字值或变量值进行更改,如 SELECT 和 UPDATE 中的 WHERE,UPDATE 语句中的 SET 和 INSERT 语句中的VALUES。
  • 防范SQL注入攻击。参数值可以包含未转义的SQL引号和分隔符。

本文编写Java程序,执行常规SQL语句和预处理语句,对比性能差异,量化预处理语句的性能提升。

1. 程序设计

通过Java程序进行DML操作,每次DML的数量是10万条,每50条一个提交批次。对比执行预处理语句和普通SQL语句,通过执行时间长短,判断执行的性能。

  • 函数 testInsertPerformance 对比 INSERT 性能;
  • 函数 testUpdatePerformance 对比 UPDATE 性能;
  • 函数 testSelectPerformance 对比 SELECT 性能;
  • 函数 testDeletePerformance 对比 DELETE 性能;

1.1 测试表

greatsql> CREATE DATABASE IF NOT EXISTS testdb1;
greatsql> USE testdb1;

greatsql> CREATE TABLE IF NOT EXISTS test_table (
    id INT AUTO_INCREMENT PRIMARY KEY,
    col1 INT,
    col2 VARCHAR(100),
    col3 DATETIME
);

1.2 Java程序代码

Java程序比较容易使用预处理SQL语句,主要有两点:

  • 数据库连接字符串中增加useServerPrepStmts=true;
  • SQL语句使用conn.prepareStatement进行预处理;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Date;

public class SqlPerformanceTest {

    private static final String URL = "jdbc:mysql://192.168.134.208:3307/testdb1?useServerPrepStmts=true";
    private static final String USER = "testuser";
    private static final String PASSWORD = "testpass";
    private static final int NUM_ITERATIONS = 100000;
    private static final int BATCH_SIZE = 50;

    public static void main(String[] args) {
        try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD)) {
            // 清空测试表
            clearTable(conn);
            // 测试 INSERT 操作
            testInsertPerformance(conn);
            // 测试 UPDATE 操作
            testUpdatePerformance(conn);
            // 测试 SELECT 操作
            testSelectPerformance(conn);
            // 测试 DELETE 操作
            testDeletePerformance(conn);

        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
    private static void clearTable(Connection conn) throws Exception {
        try (Statement stmt = conn.createStatement()) {
            stmt.execute("TRUNCATE TABLE test_table");
        }
    }
    private static void testInsertPerformance(Connection conn) throws Exception {
        long startTime, endTime;

        // 清空测试表
        clearTable(conn);

       // 普通 SQL 语句
        startTime = System.nanoTime();
        conn.setAutoCommit(false); // 关闭自动提交
        try (Statement stmt = conn.createStatement()) {
            for (int i = 1; i <= NUM_ITERATIONS; i++) {
                stmt.executeUpdate("INSERT INTO test_table (id, col1, col2, col3) VALUES ("+ i + "," + i + ", 'value" + i + "', '" + new Timestamp(new Date().getTime()) + "')");
                if (i % BATCH_SIZE == 0) {
                    conn.commit(); // 每50条记录提交一次事务
                }
            }
            conn.commit(); // 提交剩余的记录
        } finally {
            conn.setAutoCommit(true); // 恢复自动提交
        }
        endTime = System.nanoTime();
        System.out.println("INSERT - Statement: " + (endTime - startTime) / 1000000.0 + " ms");

        // 清空测试表
        clearTable(conn);

        // 预处理 SQL 语句
        startTime = System.nanoTime();
        conn.setAutoCommit(false); // 关闭自动提交
        try (PreparedStatement pstmt = conn.prepareStatement("INSERT INTO test_table (id,col1, col2, col3) VALUES (?, ?, ?, ?)")) {
            for (int i = 1; i <= NUM_ITERATIONS; i++) {
                pstmt.setInt(1, i);
                pstmt.setInt(2, i);
                pstmt.setString(3, "value" + i);
                pstmt.setTimestamp(4, new Timestamp(new Date().getTime()));
                pstmt.executeUpdate();
                if (i % BATCH_SIZE == 0) {
                    conn.commit(); // 每50条记录提交一次事务
                }
            }
            conn.commit(); // 提交剩余的记录
        } finally {        
            conn.setAutoCommit(true); // 恢复自动提交
        }
        endTime = System.nanoTime();
        System.out.println("INSERT - PreparedStatement: " + (endTime - startTime) / 1000000.0 + " ms");
    }

    private static void testUpdatePerformance(Connection conn) throws Exception {
        long startTime, endTime;

        // 普通 SQL 语句
        startTime = System.nanoTime();
        conn.setAutoCommit(false); // 关闭自动提交
        for (int i = 1; i <= NUM_ITERATIONS; i++) {
            try (Statement stmt = conn.createStatement()) {
                stmt.executeUpdate("UPDATE test_table SET col1 = " + i + ", col2 = 'value" + i + "', col3 = '" + new Timestamp(new Date().getTime()) + "' WHERE id = " + i);
                if (i % BATCH_SIZE == 0) {
                    conn.commit(); // 每50条记录提交一次事务
                }
            }
        }
        conn.commit(); // 提交剩余的记录
        endTime = System.nanoTime();
        System.out.println("UPDATE - Statement: " + (endTime - startTime) / 1000000.0 + " ms");

        // 预处理 SQL 语句
        startTime = System.nanoTime();
        conn.setAutoCommit(false); // 关闭自动提交
        try (PreparedStatement pstmt = conn.prepareStatement("UPDATE test_table SET col1 = ?, col2 = ?, col3 = ? WHERE id = ?")) {
            for (int i = 1; i <= NUM_ITERATIONS; i++) {
                pstmt.setInt(1, i);
                pstmt.setString(2, "value" + i);
                pstmt.setTimestamp(3, new Timestamp(new Date().getTime()));
                pstmt.setInt(4, i);
                pstmt.executeUpdate();
                if (i % BATCH_SIZE == 0) {
                    conn.commit(); // 每50条记录提交一次事务
                }
            }
            conn.commit(); // 提交剩余的记录
        } finally {
            conn.setAutoCommit(true); // 恢复自动提交
        }
        endTime = System.nanoTime();
        System.out.println("UPDATE - PreparedStatement: " + (endTime - startTime) / 1000000.0 + " ms");
    }

    private static void testDeletePerformance(Connection conn) throws Exception {
        long startTime, endTime;

        // 普通 SQL 语句
        startTime = System.nanoTime();
        conn.setAutoCommit(false); // 关闭自动提交
        for (int i = 1; i <= NUM_ITERATIONS/2; i++) {
            try (Statement stmt = conn.createStatement()) {
                stmt.executeUpdate("DELETE FROM test_table WHERE id = " + i);
                if (i % BATCH_SIZE == 0) {
                    conn.commit(); // 每50条记录提交一次事务
                }
            }
        }
        conn.commit(); // 提交剩余的记录
        endTime = System.nanoTime();
        System.out.println("DELETE - Statement: " + (endTime - startTime) / 1000000.0 + " ms");

        // 预处理 SQL 语句
        startTime = System.nanoTime();
        conn.setAutoCommit(false); // 关闭自动提交
        try (PreparedStatement pstmt = conn.prepareStatement("DELETE FROM test_table WHERE id = ?")){
            for (int i = NUM_ITERATIONS/2+1; i <= NUM_ITERATIONS; i++) {
                pstmt.setInt(1, i);
                pstmt.executeUpdate();
                if (i % BATCH_SIZE == 0) {
                    conn.commit(); // 每50条记录提交一次事务
                }
            }
            conn.commit(); // 提交剩余的记录
        } finally {
            conn.setAutoCommit(true); // 恢复自动提交
        }
        endTime = System.nanoTime();
        System.out.println("DELETE - PreparedStatement: " + (endTime - startTime) / 1000000.0 + " ms");
    }

    private static void testSelectPerformance(Connection conn) throws Exception {
        long startTime, endTime;

        // 普通 SQL 语句
        startTime = System.nanoTime();
        for (int i = 1; i <= NUM_ITERATIONS; i++) {
            try (Statement stmt = conn.createStatement()) {
                ResultSet rs = stmt.executeQuery("SELECT * FROM test_table WHERE id = " + i);
                while (rs.next()) {
                    // 处理结果集
                }
            }
        }
        endTime = System.nanoTime();
        System.out.println("SELECT - Statement: " + (endTime - startTime) / 1000000.0 + " ms");

        // 预处理 SQL 语句
        startTime = System.nanoTime();
        try (PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM test_table WHERE id = ?")) {
            for (int i = 1; i <= NUM_ITERATIONS; i++) {
                pstmt.setInt(1, i);
                ResultSet rs = pstmt.executeQuery();
                while (rs.next()) {
                    // 处理结果集
                }
            }
        }
        endTime = System.nanoTime();
        System.out.println("SELECT - PreparedStatement: " + (endTime - startTime) / 1000000.0 + " ms");
    }
}

2. 程序编译与运行

编译Java程序

javac -cp .:mysql-connector-j-8.0.32.jar SqlPerformanceTest.java

运行Java程序

java -cp .:mysql-connector-j-8.0.32.jar SqlPerformanceTest

3. 运行结果

$ java -cp .:mysql-connector-j-8.0.32.jar SqlPerformanceTest
INSERT - Statement: 27089.435867 ms
INSERT - PreparedStatement: 24166.424328 ms
UPDATE - Statement: 32034.818767 ms
UPDATE - PreparedStatement: 29688.13851 ms
SELECT - Statement: 23330.719737 ms
SELECT - PreparedStatement: 20430.097589 ms
DELETE - Statement: 14933.753122 ms
DELETE - PreparedStatement: 13325.930952 ms

多运行Java程序,结果接近,按照其中一次进行数据统计:

操作类型常规SQL语句执行时间(ms)预处理语句执行时间(ms)性能提升(%)
INSERT270892416610.79
UPDATE32034296887.32
SELECT233302043012.43
DELETE149331332510.77
合计973868760910.04

4. 总结

由于预处理语句比常规SQL语句,节省了SQL语句的解析时间,对于重复执行的SQL语句,使用预处理语句,可以明显地提高执行效率,性能提升约10%。

MySQL安全与审计之:`MySQL`的`SQL`注入:`预处理语句`和`参数化查询`的防御原理。 在上述例子中,无论用户输入什么内容,都会被视为参数值,而不会被解释为 SQL 代码。这确保了 SQL 注入攻击无法成功。 阅读详情

相关推荐

Java程序员如何提升技能

Java语言是大学计算机专业中常见的一门编程专业课,自己作为一名程序员,工作还在继续使用,发现大学中学的过于浅显,越来越觉得技能不够用,还需要继续深入学习。 Java基本上是目前应用最广,能力最强大的编程语言。如果精通Java,学习其它编程语言基本上都非常轻松。可是,反问自己,用Java做过多少项目,完成过什么应用系统,解决过什么难题,能独立开发APP应用么?好像还是没有多少底气,感觉浪费这强大的编程语言了。 Java编程语言真的非常强大,强大到它基本可以出色完成任何任务,所以我想好好的再次深入学习一下Ja

zihong522的博客 8560

预处理语句Java

我整理的一些关于【Java】的项目学习资料(附讲解~~)和大家一起分享、学习一下:https://d.51cto.com/f2PFnNJava中的预处理语句:提升数据库操作效率的利器 在现代软件开发中,数据库操作是至关重要的一环。无论是 web 应用程序还是企业级应用,开发人员都需要频繁地与数据库进行交互。在 Java ...

weixin_33918202的博客 235

开发 Java 应用使用 TiDB 的最佳实践

本文从常用的和数据库交互的Java组件的角度,阐述了开发Java应用程序使用TiDB的常见问题与解决办法。TiDB是高度兼容MySQL协议的数据库,基于MySQL开发的Java应用的最佳实践也多适用于TiDB。欢迎大家在ASKTUG踊跃发言,和我们一起分享讨论Java应用使用TiDB的实践技巧或遇到的问题。httpshttps。...

weixin_42241611的博客 1587

Java使用预处理语句//通用查询//虚拟存储器管理

使用预处理语句 Java提供了效率更高的数据库处理操作,就是PreparedStatement对象. 使用预处理语句的优点 由于连接器对象调用createStatement()产生一个对象然后调用executeQuery(String sql)方法是将SQL语句发送到数据库然后数据库再将其编译成自己能明白的命令,当数据量大的时候就会影响执行的速度,那么通过预处理的目的就是将SQL语句先进行编译后在发送到数据库,从此提高执行效率 方法就是使用Connection和某个数据库建立连接后的对象调用prepared

想带狗熊去吹风 1587

JAVA100例之实例54 使用语句预处理

JAVA100例之实例54 使用语句预处理

嵌入式学习的书单推荐

以上是一些优秀的嵌入式学习书单推荐。选择适合自己的学习材料对于学习嵌入式系统非常重要。每一本书籍都有其独特的优势和特点,读者可以根据自己的学习目标和兴趣选择合适的书籍。同时,我们也要注意不断实践和探索,结合实际项目和项目经验,不断提升自己的嵌入式技术水平。希望本文的推荐能够帮助大家在嵌入式学习的道路上取得更好的成果。

新程序圆 1980

java中使用预处理的优势

Java迭代器是一种用于遍历集合类(如List、Set、Map等)中元素的接口。它提供了一种统一的遍历方式,可以避免使用传统的for循环或者foreach循环时可能出现的越界等问题。3. remove():从基础集合中移除迭代器返回的最后一个元素。2. hasNext():如果迭代具有更多元素,则返回true。1. next():返回迭代中的下一个元素。

weixin_69026046的博客 580

整合Springboot+MybatisPlus+达梦数据库

整合Springboot+MybatisPlus+达梦数据库,以及一些坑

波波的博客 6677

【编译原理课程设计一】 --- Java实现 预处理+标识符的识别+词法分析

词法分析:包含预处理,标识符的识别,词法分析

qq_62711363的博客 879

避坑指南:海康MV_CC_SetIntValue接口的7个典型报错解决方案

本文深度解析海康工业相机SDK中MV_CC_SetIntValue接口的典型报错,提供7个实战解决方案。针对MV_E_CALLORDER、MV_E_PARAMETER等高频错误码,从设备状态、参数值域、依赖关系等核心约束入手,给出清晰的诊断流程与根治代码,帮助开发者构建健壮的参数设置模块,提升开发效率。

y2z3a4b5c的博客 1078

用HFSS仿真平面线圈的电感量

平面线圈是指在平面上绕制而成的线圈,如PCB上的电感线圈、无线供电使用的金属丝绕制而成的线圈等。根据线圈的不同形状可将平面线圈分为方形线圈,六角形线圈、八角形线圈、螺旋原型线圈等。

johnboat的专栏 1万+

java预处理命令_常用C/C++预处理指令详解

预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。预处理命令以符号“#”开头。常用的预处理指令包括:宏定义:#define文件包含:#include条件编译:#if、#elif、#ifndef、#ifdef、#endif、#undef错误信息指令:#error#line指令布局控制:#pragma宏定义宏定义又称为宏代换、宏替换,简称“宏”。宏替换只作替换,不做计算,...

weixin_35838019的博客 850

《遥感大模型生产级实战:从数据到决策的端到端AI工程》系列第一部分:AI遥感工程师的基础设施与工具链-文章 4:传统遥感分析与机器学习基线

本章将系统性地介绍经典遥感分析工作流,从数据预处理到多维度特征工程,再到如何利用经典的机器学习模型(如随机森林、支持向量机)进行监督与非监督学习。我们将通过一个完整的“智慧农业作物分类”项目实战,展示如何利用我们之前构建的数据湖和工具链,从原始数据到最终的分析结果,构建一个性能可靠、可解释性强的基线系统。更重要的是,我们将深入剖析这种传统方法的局限性,从而为后续章节引入遥感大模型的必要性提供强有力的论证。

panshengwu的博客 705

为什么预处理对象会提升处理的性能

⭐本篇文章主要环绕 “预处理对象会提升处理的性能” 这个问题做出解答以及关于预处理部分理论知识

Jin_Xiang123的博客 1356

GE Proficy Historian8.0历史数据库部署与配置全攻略

本文提供了GE Proficy Historian 8.0历史数据库的详细部署与配置指南。内容涵盖安装前的系统环境、权限与依赖检查,服务器安装的关键步骤与类型选择,采集器的安装配置与数据接入,以及客户端工具的使用与数据分析实战。旨在帮助用户规避常见陷阱,实现一次部署成功,构建稳定高效的工业数据归档平台。

silver的专栏 767

80MHz~100MHz频谱分析仪设计

由理论分析可知,经过乘法器后输出的信号为频率为w1+w2的高频信号和w1-w2的低频信号,除了想要采样的直流信号外,最小的信号频率为100kHz。因此,经过一系列推导可以得到该滤波器的元件C1,C2,C3,R1,R2的近似值分别为:C1=2.36nF,C2=32.1nF,C3=1.07nF,R1=1.39k,R2=2.84k。AK,此时的频率w2即为被测信号的频率,待测信号源电压幅度为,因此为了能达到直流采样的设计,我们将本振源的频率输出范围做成80~110 MHz,提高了题目的频率要求。

qq_48771816的博客 5242

深入解析 MySQL 预处理语句:安全与性能的双重保障

在现代 Web 应用和数据库系统中,安全性与执行效率始终是开发者关注的核心问题。而 MySQL 提供的预处理语句(Prepared Statements)正是解决这两个关键痛点的强大工具。它不仅能够有效防范 SQL 注入攻击,还能显著提升高频查询的执行性能。本文将从原理、优势、使用方式到最佳实践,全面剖析 MySQL 预处理语句的价值,并帮助你真正掌握这一数据库开发中的“黄金标准”。预处理语句是一种预编译的 SQL 模板,其核心思想是将 SQL 的结构(逻辑)与数据(参数)分离。

用文字记录技术,用分享回馈社区,用坚持见证成长 917

Kubernetes(K8s)从入门到精通系列之一:一篇文章了解K8s全部核心知识点

Kubernetes(K8s)从入门到精通系列之一:一篇文章了解K8s全部核心知识点

zhengzaifeidelushang的博客 849

学习预处理语句;并使用预处理语句添加记录

预处理语句 定义: 你可以把它们想成是一种编译过的要执行的SQL语句模板,可以使用不同的变量参数定制它。 优点: 效率高 (用于执行多个相同的 SQL 语句,并且执行效率更高) 预处理语句大大减少了分析时间,只做了一次查询(虽然语句多次执行) 因为服务器缓存了一部分执行计划,所以它只需要度执行某些优化步骤一次 通过二进制发送参数比通过ASCII 码要快的多。比如,通过二进制发送DATE 类型的参...

Z1998hx0919的博客 657

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

NTscan扫描工具

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

MySQL:Prepared Statement 预处理语句

预处理语句(Prepared Statement)是一种在数据库管理系统中使用的编程概念,用于执行对数据库进行操作的 SQL 语句。 使用预处理语句的具体方式和语法依赖于所用的编程语言和数据库管理系统。常见的编程语言如 *Java、PHP、Python* 和 *C#* 都提供了对预处理语句的支持。

热带鱼的技术博客 1305

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

java mysql 预处理指令_MySQL预处理

MySQL的预处理在一定程度上可以提升程序运行效率。普通的SQL语句每次都需要经过词法和语义解析,优化 SQL 语句并制定执行计划。对于多次执行相同SQL语句的情况,MySQL预处理省去解析优化过程,提高运行效率。另外预处理可以防止客户端 SQL 注入。C++预处理接口: preparable_stmt 语句中的? 是个占位符,字符串类型需要加上单引号。 创建预处理对象sql::Prepared...

weixin_28723171的博客 562

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

JMeter JSR223预处理程序全攻略:用Groovy解锁复杂场景自动化

JMeter的JSR223预处理程序是处理复杂性能测试场景的利器,支持Groovy等脚本语言实现动态签名、参数加密、数据组装等自定义逻辑。本文详细解析其核心用法,包括基础配置、内置对象操作,以及四大实战场景:生成MD5接口签名、AES加密请求体、动态组装JSON和数据库查询数据注入。同时提供性能优化技巧和常见问题解决方案,帮助测试人员突破JMeter内置组件限制,高效完成各类复杂参数处理需求。关键点包括优先使用Groovy语言、合理缓存脚本、优化资源消耗以及完善的调试机制。

m0_58868237的博客 2071

mysql 预处理理解,理解Mysql prepare预处理语句

MySQL 5.1对服务器一方的预制语句提供支持。如果您使用合适的客户端编程界面,则这种支持可以发挥在MySQL 4.1中实施的高效客户端/服务器二进制协议的优势。候选界面包括MySQL C API客户端库(用于C程序)、MySQL Connector/J(用于Java程序)和MySQL Connector/NET。例如,C API可以提供一套能组成预制语句API的函数调用。其它语言界面可以对使用...

weixin_36174245的博客 490

Java性能权威指南-总结23

警如,应用程序运行的服务器比较弱,是个双核的机器,它连接的是一个性能强大、调优良好的数据库服务器,那么在这种情况下,很可能应用还没施加多大的压力到数据库,应用服务器自身的CPU就已经达到了100%。典型的情况下,这种设置能取得最好的性能:所有的程序线程都不需要等待数据库连接的释放,数据库亦有足够的资源处理来自应用程序的负荷。对于JDBC驱动程序的性能要保持谨慎怀疑的态度:经常会出现这样的情况,即某个驱动程序在特定的环境下表现的性能优于其他供应商,但在自己的环境中,采用同样的配置效果却不尽人意。

weixin_42583701的博客 395

提升JAVA程序的性能

  随着时间的推移,Java虚拟机变得越来越好,但是通过一些简单的技巧,你仍然可以明显地改进程序的性能。 简介Java的诸多优点已经广为称道。特别是“一次编程,到处运行”的承诺使开发人员可以自由地进行跨平台应用程序的开发而不存在预处理器指令的开销。通常认为Java的弱点在于其性能方面。在当前这种认识并不是完全正确的,有很多产品可以提高Java程序的性能并能够使其在很多应用程

mashy的专栏 917
上一篇: GreatSQL启动崩溃:jemalloc依赖缺失问题排查
下一篇: 使用 gt-checksum 分析迁移对象
GreatSQL社区
博客等级 码龄5年 1210粉丝 390原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值