数据库连接池与DBUtils工具、DataSource接口、 DBCP数据库连接池、C3P0数据库连接池、DBUtils类、QueryRunner类、ResultSetHandler实现类、增删改查

数据库连接池与DBUtils工具

​ JDBC的基本用法和操作,每操作一次数据库,都会执行一次创建和断开Connection对象的操作,频繁的操作Connection对象十分影响数据库的访问效率,并且增加了代码量,所以在实际开发中,开发人员通常会使用数据库连接池来解决这些问题。Apache组织提供了一个DBUtils工具类库,该类库实现了对JDBC的简单封装,能在不影响数据库访问性能的情况下,极大地简化JDBC的编码工作。

01. 数据库连接池

​ 在JDBC编程中,每次创建和断开Connection对象都会消耗一定的时间和IO资源。在Java程序与数据库之间建立连接时,数据库端要验证用户名和密码,并且要为这个连接分配资源,Java程序则要把代表连接的java.sql.Connection对象等加载到内存中,所以建立数据库连接的开销很大,尤其是在大量的并发访问时。假如某网站一天的访问量是10万,那么该网站的服务器就需要创建、断开连接10万次,频繁地创建、断开数据库连接会影响数据库的访问效率,甚至导致数据库崩溃。

​ 为了避免频繁的创建数据库连接,数据库连接池技术应运而生。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用现有的数据库连接,而不是重新建立。简单地说,数据库连接池就是为数据库建立的一个“缓冲池”。预先在“缓冲池”中放入一定数量的连接,当需要建立数据库连接时,只需要从“缓冲池”中取出一个,使用完毕后再放回“缓冲池”即可。

在这里插入图片描述

​ 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,当应用程序访问数据库时并不是直接创建Connection,而是向连接池“申请”一个Connection。如果连接池中有空闲的Connection,则返回一个链接给应用程序,否则应用程序需要创建新的Connection。使用完毕后,连接池会将Connection回收,重新放入连接池以供其他的线程使用,从而减少创建和断开数据库连接的次数,提高数据库的访问效率。

01. DataSource接口
为了获取数据库连接对象(Connection),JDBC提供了javax.sql.DataSource接口,javax.sql.DataSource接口负责
与数据库建立连接,并定义了返回值为Connection对象的方法,具体如下。
Connection getConnection() 。
Connection getConnection(String username, String password)。

注意:上述两个重载的方法,都能用来获取Connection对象。不同的是,第一个方法是通过无参的方式建立与数据库的连
接,第二个方法是通过传入登录信息的方式建立与数据库的连接。

接口通常都会有实现类,javax.sql.DataSource接口也不例外,通常习惯性的把实现了javax.sql.DataSource接口的类
称为数据源,顾名思义,数据源即数据的来源。每创建一个数据库连接,这个数据库连接信息都会存储到数据源中。 

数据源用于管理数据库连接池。如果数据是水,数据库就是水库,数据库连接池就是连接到水库的管道,终端用户看到的数
据集是管道里流出来的水。一些开源组织提供了数据库连接池的独立实现,常用的有DBCP数据库连接池和C3P0数据库连接
池。

02. DBCP数据库连接池
DBCP即数据库连接池(DataBase Connection Pool),是Apache组织下的开源连接池实现,也是Tomcat服务器使用的连
接池组件。使用DBCP数据库连接池时,需要在应用程序中导入commons-dbcp2.jar和commons-pool2.jar两个JAR包。

commons-dbcp2.jar包是DBCP数据库连接池的实现包,包含所有操作数据库连接信息和数据库连接池初始化信息的方法,
并实现了DataSource接口的getConnection()方法。

commons-pool2.jar包是commons-dbcp2.jar包的依赖包,为commons-dbcp2.jar包中的方法提供了支持。缺少该依赖
包,commons-dbcp2.jar包中的很多方法就没有办法实现。

commons-dbcp2.jar包含两个核心类,分别是BasicDataSourceFactory和BasicDataSource,它们都包含获取DBCP数据库连接池对象的方法。

BasicDataSource类的常用方法

方法名称功能描述
void setDriverClassName(String driverClassName)设置连接数据库的驱动名称
void setUrl(String url)设置连接数据库的路径
void setUsername(String username)设置数据库的登录账号
void setPassword(String password)设置数据库的登录密码
void setInitialSize(int initialSize)设置数据库连接池初始化的连接数目
void setMinIdle(int minIdle)设置数据库连接池最小闲置连接数目
Connection getConnection()从连接池中获取一个数据库连接
BasicDataSource对象的常用方法中setDriverClassName()、setUrl()、setUsername()、setPassword()等
方法都是设置数据库连接信息的方法;setInitialSize()、setMinIdle()等方法都是设置数据库连接池初始化
值的方法;getConnection()方法可以从DBCP数据库连接池中获取一个数据库连接。

BasicDataSourceFactory是创建BasicDataSource对象的工厂类,它包含一个返回值为BasicDataSource类型的方法createDataSource(),该方法通过读取配置文件的信息生成数据源对象并返回给调用者。把数据库的连接信息和数据源的初始化信息提取出来写进配置文件,这样让代码看起来更加简洁,思路也更加清晰。

创建数据源对象—通过BasicDataSource类直接创建数据源对象

项目中导入mysql-connector-java-8.0.15.jar、commons-dbcp2-2.7.0.jar、commons-logging-1.2.jar以commons-pool2-2.8.0.jar四个JAR包


package com.miao.jdbcutils;

import org.apache.commons.dbcp2.BasicDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/31
 * \* Time: 10:29
 * \* Description:
 * \
 */
public class Demo01 {

    public static DataSource ds = null;

    static {
//        获取DBCP数据库链接池实现类对象
        BasicDataSource basicDataSource = new BasicDataSource();
//        设置数据库链接需要的配置信息
        basicDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        basicDataSource.setUrl("jdbc:mysql://localhost:3306/jdbc?serverTimezone=GMT%2B8");
        basicDataSource.setUsername("root");
        basicDataSource.setPassword("123456");
//        设置连接池的初始化参数
        basicDataSource.setInitialSize(5);
        ds = basicDataSource;
    }

    public static void main(String[] args) throws SQLException {
//        获取数据库链接对象
        Connection connection = ds.getConnection();
//        获取数据库连接信息
        DatabaseMetaData metaData = connection.getMetaData();
//        打印数据库链接信息
        System.out.println(metaData.getURL()+", Username:"+ metaData.getUserName()+ "," +metaData.getDriverName());
    }
}

在这里插入图片描述

创建数据源对象—通过读取配置文件创建数据源对象

BasicDataSourceFactory工厂类读取配置文件,创建数据源对象,然后获取数据库连接对象。下面通过一个案例演示通过读取配置文件创建数据源对象。

package com.miao.jdbcutils;

import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Properties;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/31
 * \* Time: 10:29
 * \* Description:
 * \
 */
public class Demo02 {

    public static DataSource ds = null;

    static {

//        新建一个配置文件对象
        Properties properties = new Properties();

        try {
//        通过类加载器找到文件路径,读取配置文件
            InputStream resourceAsStream = new Demo02().getClass().getClassLoader().getResourceAsStream("dbcpconfig.properties");
//        把文件以输入流的形式加载到配置对象中
            properties.load(resourceAsStream);
//            创建数据源对象
            ds = BasicDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws SQLException {
//        获取数据库链接对象
        Connection connection = ds.getConnection();
//        获取数据库连接信息
        DatabaseMetaData metaData = connection.getMetaData();
//        打印数据库链接信息
        System.out.println(metaData.getURL()+", Username:"+ metaData.getUserName()+ "," +metaData.getDriverName());
    }
}
#连接设置
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc?serverTimezone=GMT%2B8
username=root
password=123456
#初始化连接
initialSize=5
#最大空闲连接
maxIdle=10

在这里插入图片描述

03. C3P0数据库连接池

C3P0是目前最流行的开源数据库连接池之一,它实现了DataSource数据源接口,支持JDBC2和JDBC3的标准规范,易于扩展
并且性能优越,著名的开源框架Hibernate和 Spring都支持该数据库连接池。在使用C3P0数据库连接池开发时,需要了解
C3P0中DataSource接口的实现类ComboPooledDataSource,它是C3P0的核心类,提供了数据源对象的相关方法。

ComboPooledDataSource类的常用方法

当使用C3P0数据库连接池时,首先需要创建数据源对象,创建数据源对象可以通过调用ComboPooledDataSource
类的构造方法实现。ComboPooledDataSource类有两个构造方法,分别是ComboPooledDataSource()和
ComboPooledDataSource(String configName)。

通过ComboPooledDataSource()构造方法创建数据源对象

package com.miao.jdbcutils;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Properties;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/31
 * \* Time: 10:29
 * \* Description:
 * \
 */
public class Demo03 {

    public static DataSource ds = null;

    static {

        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

//         设置数据库链接需要的配置信息
        try {
            comboPooledDataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
            comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc?serverTimezone=GMT%2B8");
            comboPooledDataSource.setUser("root");
            comboPooledDataSource.setPassword("123456");

//            设置连接池参数
            comboPooledDataSource.setMaxPoolSize(10);
            comboPooledDataSource.setInitialPoolSize(5);
            ds = comboPooledDataSource;
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }


    }

    public static void main(String[] args) throws SQLException {
        System.out.println(ds.getConnection());
    }
}

在这里插入图片描述

通过ComboPooledDataSource(String configName)构造方法创建数据源对象

调用ComboPooledDataSource(String configName)构造方法可以读取c3p0-config.xml配置文件,根据配置
文件中的配置信息创建数据源对象,然后获取数据库连接对象。

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">
            jdbc:mysql://localhost:3306/jdbc?serverTimezone=GMT%2B8
        </property>
        <property name="user">root</property>
        <property name="password">root</property>
        <property name="checkoutTimeout">30000</property>
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
    </default-config>
    <named-config name="itcast">
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">
            jdbc:mysql://localhost:3306/jdbc?serverTimezone=GMT%2B8
        </property>
        <property name="user">root</property>
        <property name="password">123456</property>
        <property name="initialPoolSize">5</property>
        <property name="maxPoolSize">15</property>
    </named-config>
</c3p0-config>
package com.miao.jdbcutils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.sql.SQLException;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/31
 * \* Time: 10:29
 * \* Description:
 * \
 */
public class Demo04 {

    public static DataSource ds = null;

    static {
//        使用c3p0-config.xml配置文件中的named-config节点中的name属性
        ComboPooledDataSource c3p0config = new ComboPooledDataSource("c3p0config");
        ds = c3p0config;
    }

    public static void main(String[] args) throws SQLException {
        System.out.println(ds.getConnection());
    }
}

在这里插入图片描述

02. DBUtils工具

为了更加简单地使用JDBC,Apache组织提供了一个DBUtils工具,它是操作数据库的一个组件,实现了对JDBC的简单封
装,可以在不影响数据库访问性能的情况下简化JDBC的编码工作量。DBUtils工具要有三个作用。

写数据,DBUtils可以通过编写SQL语句对数据表进行增、删、改操作。
读数据,DBUtils工具可以将从数据表中读取的数据结果集转换成Java常用类集合,以方便对结果进行处理。
优化性能,在使用DBUtils工具的基础上,程序可以使用数据源、JNDI、数据库连接池等技术减少代码冗余。

DBUtils核心类库主要包括DBUtils类、QueryRunner类和ResultSetHandler接口。DBUtils工具主要通过这三个核心API
进行JDBC的所有操作。

在这里插入图片描述

01. DBUtils类
DBUtils类主要提供了加载JDBC驱动、关闭资源等方法,DBUtils类中的方法一般为静态方法,可以直接使用类名进行调
用。

DBUtils类的常用方法

方法名称功能描述
void close(Connection conn)当连接不为NULL时,关闭连接
void close(Statement stat)当声明不为NULL时,关闭声明
void close(ResultSet rs)当结果集不为NULL时,关闭结果集
void closeQuietly(Connection conn)当连接不为NULL时,关闭连接,并隐藏一些在程序中抛出的SQL异常
void closeQuietly(Statement stat)当声明不为NULL时,关闭声明,并隐藏一些在程序中抛出的SQL异常
void closeQuietly(ResultSet rs)当结果集不为NULL时,关闭结果集,并隐藏一些在程序中抛出的SQL异常
void commitAndCloseQuietly(Connection conn)提交连接后关闭连接,并隐藏一些在程序中抛出的SQL异常
Boolean loadDriver(String driveClassName)装载并注册JDBC驱动程序,如果成功就返回true
02. QueryRunner类
QueryRunner类简化了执行SQL语句的代码,它与ResultSetHandler配合就能完成大部分的数据库操作,大大减少了编码
量。QueryRunner类提供了带有一个参数的构造方法,该方法以javax.sql.DataSource的实例对象作为参数传递到
QueryRunner的构造方法中来获取Connection对象。针对不同的数据库操作,QueryRunner类提供不同的方法。

QueryRunner类的常用方法

方法名称功能描述
Object query(Connection conn,String sql,ResultSetHandler rsh,Object[] params)执行查询操作,传入的Connection对象不能为空
Object query (String sql, ResultSetHandler rsh,Object[] params)执行查询操作
Object query (Connection conn,String sql, ResultSetHandler rsh)执行一个不需要置换参数的查询操作
int update(Connection conn, String sql, ResultSetHandler rsh)执行一个更新(插入、删除、更新)操作
int update(Connection conn, String sql)执行一个不需要置换参数的更新操作
int batch(Connection conn,String sql, Object[] []params)批量添加、修改、删除
int batch(String sql, Object[][] params)批量添加、修改、删除
03. ResultSetHandler接口
ResultSetHandler接口用于处理ResultSet结果集,它可以将结果集中的数据转换为不同的形式。根据结果集中不同的数
据类型,ResultSetHandler提供了几种常见的实现类。
BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,并存放到List里。
ColumnListHandler:将某列属性的值封装到List集合中。
ScalarHandler:将结果集中某一条记录的某一列数据存储成Object对象。

ResultSetHandler接口还提供了一个单独的方法handle (java.sql.ResultSet rs),如果上述实现类没有提供想要的功
能,可以自定义一个实现ResultSetHandler接口的类,然后通过重写handle()方法,实现结果集的处理。

04. ResultSetHandler实现类
BeanHandler和BeanListHandler实现类是将结果集中的数据封装到对应的JavaBean中。在封装时,表中数据的字段和
JavaBean的属性是相互对应的,一条数据记录被封装进一个对应的JavaBean对象中。BeanHandler和BeanListHandler的
对比如下表所示。

类名称相同点不同点
BeanHandler都要先将结果集封装进JavaBean封装单条数据,把结果集的第一条数据的字段放入一个JavaBean中
BeanListHandler封装多条数据,把每条数据的字段值各放入一个JavaBean中,再把所有JavaBean都放入List集合中

BasseDao.java


package com.miao.jdbcutils;

import org.apache.commons.dbutils.ResultSetHandler;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/31
 * \* Time: 11:28
 * \* Description:
 * \
 */
public class BaseDao {

    // 优化查询
    public static Object query(String sql, ResultSetHandler<?> rsh,
                               Object... params) throws SQLException {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            // 获得连接
            conn = JDBCUtils.getConnection();
            // 预编译sql
            pstmt = conn.prepareStatement(sql);
            // 将参数设置进去
            for (int i = 0; params != null && i < params.length; i++)
            {
                pstmt.setObject(i + 1, params[i]);
            }
            // 发送sql
            rs = pstmt.executeQuery();
            // 让调用者去实现对结果集的处理
            Object obj = rsh.handle(rs);
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 释放资源
            JDBCUtils.release(rs, pstmt, conn);
        }
        return rs;
    }
}

JDBCUtils.java

package com.miao.jdbcutils;

import java.sql.*;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/31
 * \* Time: 11:33
 * \* Description:
 * \
 */
public class JDBCUtils {

    // 加载驱动,并建立数据库连接
    public static Connection getConnection() throws SQLException,
            ClassNotFoundException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/jdbc?serverTimezone=GMT%2B8";
        String username = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url, username,
                password);
        return conn;
    }
    // 关闭数据库连接,释放资源
    public static void release(Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            stmt = null;
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn = null;
        }
    }
    public static void release(ResultSet rs, Statement stmt,
                               Connection conn){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            rs = null;
        }
        release(stmt, conn);
    }
}

User.java

package com.miao.pojo;

import java.io.Serializable;
public class User implements Serializable {

    private String name;
    private String sex;
    private int age;

    public User() {
    }

    public User(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }
}

ResultSet01

package com.miao.jdbcutils;

import com.miao.pojo.User;
import org.apache.commons.dbutils.handlers.BeanHandler;
import java.sql.SQLException;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/31
 * \* Time: 11:44
 * \* Description:
 * \
 */
public class ResultTest01 {
    public static void testBeanHandler() throws SQLException {
        BaseDao basedao = new BaseDao();
        String sql = "select * from users where id=?";
        User user = (User) basedao.query(sql,
                new BeanHandler(User.class), 1);
        System.out.print("id为1的User对象的name值为:" + user.getName());
    }
    public static void main(String[] args) throws SQLException {
        testBeanHandler();
    }
}

在这里插入图片描述

package com.miao.jdbcutils;

import com.miao.pojo.User;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.SQLException;
import java.util.ArrayList;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/31
 * \* Time: 11:44
 * \* Description:
 * \
 */
public class ResultTest02 {
    public static void testBeanListHandler() throws SQLException {
        BaseDao basedao = new BaseDao();
        String sql = "select * from users ";
        ArrayList<User> list = (ArrayList<User>) basedao.query(sql,
                new BeanListHandler(User.class));
        for (int i = 0; i < list.size(); i++) {
            System.out.println("第" + (i + 1) + "条数据的username值为:"
                    + list.get(i).getName());
        }
    }
    public static void main(String[] args) throws SQLException {
        testBeanListHandler();
    }
}

在这里插入图片描述


package com.miao.jdbcutils;

import com.miao.pojo.User;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;

import java.sql.SQLException;
import java.util.ArrayList;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/31
 * \* Time: 11:44
 * \* Description:
 * \
 */
public class ResultTest03 {
    public static void testColumnListHandler() throws SQLException {
        BaseDao basedao = new BaseDao();
        String sql = "select * from users";
        Object arr = (Object) basedao.query(sql,
                new ColumnListHandler("name"));
        System.out.println(arr);
    }
    public static void main(String[] args) throws SQLException {
        testColumnListHandler();
    }
}

在这里插入图片描述

package com.miao.jdbcutils;

import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.SQLException;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/31
 * \* Time: 11:44
 * \* Description:
 * \
 */
public class ResultTest04 {
    public static void testScalarHandler() throws SQLException {
        BaseDao basedao = new BaseDao();
        String sql = "select * from users where id=?";
        Object arr = (Object) basedao.query(sql,
                new ScalarHandler("name"), 1);
        System.out.println(arr);
    }
    public static void main(String[] args) throws SQLException {
        testScalarHandler();
    }
}

在这里插入图片描述

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铲屎官白茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值