MySQL【JDBC连接池全网最详细讲解--jdbc常用类详细讲解】

10 篇文章 0 订阅

JDBC

1.1什么是 JDBC

  JDBC 规范定义接口,具体的实现由各大数据库厂商来实现。
JDBC 是 Java 访问数据库的标准规范,真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个

数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用 JDBC 接口中的方法即可,数据库驱动由数据库厂商提供。

使用 JDBC 的好处:

1).程序员如果要开发访问数据库的程序,只需要会调用 JDBC 接口中的方法即可,不用关注类是如何实现的。
2) 使用同一套 Java 代码,进行少量的修改就可以访问其他 JDBC 支持的数据库
在这里插入图片描述

3.1.2 使用 JDBC 开发使用到的包:.

在这里插入图片描述

3.2JDBC 的核心 API

在这里插入图片描述

3.3 导入驱动 Jar 包

在这里插入图片描述
在这里插入图片描述

3.4 加载和注册驱动

在这里插入图片描述
疑问:为什么这样可以注册驱动?

public class Demo1 {
	 public static void main(String[] args) throws ClassNotFoundException {
	 //抛出类找不到的异常,注册数据库驱动
	 Class.forName("com.mysql.jdbc.Driver");
 } }

com.mysql.jdbc.Driver 源代码:

public class Driver implements java.sql.Driver {
    public Driver() throws SQLException {
    }
    static {
		try {
   	 DriverManager.registerDriver(new Driver()); //注册数据库驱动
   	 } catch (SQLException var1) {
   		 throw new RuntimeException("Can't register driver!");
		}
    } 
}

注:从 JDBC3 开始,目前已经普遍使用的版本。可以不用注册驱动而直接使用。Class.forName
这句话可以省略。

2.DriverManager 类

4.1 DriverManager 作用:

  1. 管理和注册驱动
  2. 创建数据库的连接
4.2 类中的方法:

在这里插入图片描述

4.3 使用 JDBC 连接数据库的四个参数:

在这里插入图片描述

4.4 连接数据库的 URL 地址格式:
协议名:子协议://服务器名或 IP 地址:端口号/数据库名?参数=参数值
  • 4.4.1 MySQL 写法:
    在这里插入图片描述
  • 4.4.2 MySQL 中可以简写:
前提:必须是本地服务器,端口号是 3306
jdbc:mysql:///数据库名
  • 4.4.3 乱码的处理

如果数据库出现乱码,可以指定参数: ?characterEncoding=utf8,表示让数据库以 UTF-8 编码来处理数据。

jdbc:mysql://localhost:3306/数据库?characterEncoding=utf8

4.5 案例:得到 MySQL 的数据库连接对象

  1. 使用用户名、密码、URL 得到连接对象
package com.itheima;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* 得到连接对象
*/
public class Demo2 {
 	public static void main(String[] args) throws SQLException {
 		String url = "jdbc:mysql://localhost:3306/day24";
 		//1) 使用用户名、密码、URL 得到连接对象
 		Connection connection = DriverManager.getConnection(url,
 		 "root", "root");
 		//com.mysql.jdbc.JDBC4Connection@68de145
 		System.out.println(connection);
 } }
  1. 使用属性文件和 url 得到连接对象
package com.itheima;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class Demo3 {
 	public static void main(String[] args) throws SQLException {
 	//url 连接字符串
 	String url = "jdbc:mysql://localhost:3306/day24";
 	//属性对象
 	Properties info = new Properties();
 	//把用户名和密码放在 info 对象中
 	info.setProperty("user","root");
 	info.setProperty("password","root");
 	Connection connection = DriverManager.getConnection(url, info);
 	//com.mysql.jdbc.JDBC4Connection@68de145
 	System.out.println(connection);
 } }

第5节 Connection 接口:

5.1 Connection 作用:

Connection 接口,具体的实现类由数据库的厂商实现,代表一个连接对象。

5.2 Connection 方法:

在这里插入图片描述

第6节 Statement 接口

6.1 JDBC 访问数据库的步骤

在这里插入图片描述

  1. 注册和加载驱动(可以省略)
  2. 获取连接
  3. Connection 获取 Statement 对象
  4. 使用 Statement 对象执行 SQL 语句
  5. 返回结果集
  6. 释放资源
6.2 Statement 作用:

代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象

6.3Statement 中的方法:

在这里插入图片描述

6.4 释放资源
  1. 需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接
  2. 释放原则:先开的后关,后开的先关。ResultSet -> Statement -> Connection
  3. 放在哪个代码块中:finally 块
6.5 执行 DDL 操作

6.5.1 需求:使用 JDBC 在 MySQL 的数据库中创建一张学生表
在这里插入图片描述
6.5.2 代码:

package com.itheima;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 创建一张学生表
*/
public class Demo4DDL {
 	public static void main(String[] args) {
 	//1. 创建连接
 		Connection conn = null;
 		Statement statement = null;
 		try {
 			conn = DriverManager.getConnection("jdbc:mysql:///day24",
 			 "root", "root");
 			//2. 通过连接对象得到语句对象
 			statement = conn.createStatement();
 		//3. 通过语句对象发送 SQL 语句给服务器
 		//4. 执行 SQL
		 statement.executeUpdate("create table student (id int PRIMARY key auto_increment, " +
 "name varchar(20) not null, gender boolean, birthday date)");
		 //5. 返回影响行数(DDL 没有返回值)
 		System.out.println("创建表成功");
 		} catch (SQLException e) {
 			e.printStackTrace();
		}
 		//6. 释放资源
 		finally {
 			//关闭之前要先判断
 			if (statement != null) {
 				try {
 					statement.close();
 				} catch (SQLException e) {
					 e.printStackTrace();
 				}
		 }
		 if (conn != null) {
				try {
				 conn.close();
 				} catch (SQLException e) {
 						e.printStackTrace();
 				}
 		}
 	}
 }
 }
6.6 执行 DML 操作

需求:向学生表中添加 4 条记录,主键是自动增长
在这里插入图片描述
** 步骤:**

  1. 创建连接对象
  2. 创建 Statement 语句对象
  3. 执行 SQL 语句:executeUpdate(sql)
  4. 返回影响的行数
  5. 释放资源
package com.itheima;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 向学生表中添加 4 条记录,主键是自动增长
*/
public class Demo5DML {
 	public static void main(String[] args) throws SQLException {
	// 1) 创建连接对象
	 Connection connection = DriverManager.getConnection("jdbc:mysql:///day24", 
  "root","root");
// 2) 创建 Statement 语句对象
 Statement statement = connection.createStatement();
// 3) 执行 SQL 语句:executeUpdate(sql)
 int count = 0;
// 4) 返回影响的行数
 count += statement.executeUpdate("insert into student values(null, '孙悟空', 1, '1993-03-
24')");
 count += statement.executeUpdate("insert into student values(null, '白骨精', 0, '1995-03-
24')");
 count += statement.executeUpdate("insert into student values(null, '猪八戒', 1, '1903-03-24')");
 count += statement.executeUpdate("insert into student values(null, '嫦娥', 0, '1993-03-
11')");
 System.out.println("插入了" + count + "条记录");
// 5) 释放资源
 statement.close();
 connection.close();
 } }

6.7 执行 DQL 操作
  • 6.7.1 ResultSet 接口:
    作用:封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。
    在这里插入图片描述
    在这里插入图片描述
    接口中的方法:
    在这里插入图片描述
    在这里插入图片描述
    6.7.2 需求:确保数据库中有 3 条以上的记录,查询所有的学员信息
    步骤:
  1. 得到连接对象
  2. 得到语句对象
  3. 执行 SQL 语句得到结果集 ResultSet 对象
  4. 循环遍历取出每一条记录
  5. 输出的控制台上
  6. 释放资源
    在这里插入图片描述
package com.itheima;
import java.sql.*;
/**
* 查询所有的学生信息
*/
public class Demo6DQL {
 	public static void main(String[] args) throws SQLException {
 	//1) 得到连接对象
 		Connection connection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/day24",
"root","root");
 	//2) 得到语句对象
 		Statement statement = connection.createStatement();
	 //3) 执行 SQL 语句得到结果集 ResultSet 对象
	 ResultSet rs = statement.executeQuery("select * from student");
 	//4) 循环遍历取出每一条记录
 	while(rs.next()) {
 		int id = rs.getInt("id");
 		String name = rs.getString("name");
 		boolean gender = rs.getBoolean("gender");
 		Date birthday = rs.getDate("birthday");
 		//5) 输出的控制台上
 		System.out.println("编号:" + id + ", 姓名:" + name + ", 性别:" + gender + ", 生日:" +
		birthday);
	 }
 	//6) 释放资源
 	rs.close();
 	statement.close();
 	connection.close();
	} 
 }
  • 6.7.4 关于 ResultSet 接口中的注意事项
  1. 如果光标在第一行之前,使用 rs.getXX()获取列值,报错:Before start of result set
  2. 如果光标在最后一行之后,使用rs.getXX()获取列值,报错:After end of result set
  3. 使用完毕以后要关闭结果集 ResultSet,再关闭 Statement,再关闭 Connection

第7节 数据库工具类 JdbcUtils

什么时候自己创建工具类?
如果一个功能经常要用到,我们建议把这个功能做成一个工具类,可以在不同的地方重用。

7.1 需求:

上面写的代码中出现了很多重复的代码,可以把这些公共代码抽取出来。

7.2 创建类 JdbcUtil 包含 3 个方法:
  1. 可以把几个字符串定义成常量:用户名,密码,URL,驱动类
  2. 得到数据库的连接:getConnection()
  3. 关闭所有打开的资源
    close(Connection conn, Statement stmt),close(Connection conn, Statement stmt, ResultSet rs)
package com.itheima.utils;
import java.sql.*;
* 访问数据库的工具类
*/
public class JdbcUtils {
	 //可以把几个字符串定义成常量:用户名,密码,URL,驱动类
	 private static final String USER = "root";
	 private static final String PWD = "root";
 	 private static final String URL = "jdbc:mysql://localhost:3306/day24";
	 private static final String DRIVER= "com.mysql.jdbc.Driver";

 //注册驱动

	 static {
 		try {
		 Class.forName(DRIVER);
 		} catch (ClassNotFoundException e) {
 			e.printStackTrace();
 		}
 	}
 /**
 * 得到数据库的连接
 */
	 public static Connection getConnection() throws SQLException {
 		return DriverManager.getConnection(URL,USER,PWD);
 	}
 /**
 * 关闭所有打开的资源
 */
 	public static void close(Connection conn, Statement stmt) {
 		if (stmt!=null) {
 			try {
 				stmt.close();
 			} catch (SQLException e) {
 				e.printStackTrace();
 			}
 		}
 		if (conn!=null) {
			 try {
				 conn.close();
			 } catch (SQLException e) {
				 e.printStackTrace();
 			}
 		}
 }
 /**
 * 关闭所有打开的资源
 */
 public static void close(Connection conn, Statement stmt, ResultSet rs) {
 	if (rs!=null) {
		 try {
			 rs.close();
		 } catch (SQLException e) {
			 e.printStackTrace();
		}
	 }
	 close(conn, stmt);
 } }
7.3 案例:用户登陆

7.3.1 需求:

  1. 有一张用户表
  2. 添加几条用户记录
create table user (
 id int primary key auto_increment,
 name varchar(20),
 password varchar(20)
)
insert into user values (null,'jack','123'),(null,'rose','456');
//登录, SQL 中大小写不敏感
select * from user where name='JACK' and password='123';
//登录失败
select * from user where name='JACK' and password='333';
  1. 使用 Statement 字符串拼接的方式实现用户的登录, 用户在控制台上输入用户名和密码。
  • 7.3.2 步骤:
  1. 得到用户从控制台上输入的用户名和密码来查询数据库
  2. 写一个登录的方法
    a) 通过工具类得到连接
    b) 创建语句对象,使用拼接字符串的方式生成 SQL 语句
    c) 查询数据库,如果有记录则表示登录成功,否则登录失败
    d) 释放资源
package com.itheima;
import com.itheima.utils.JdbcUtils;
import javax.xml.transform.Result;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
public class Demo7Login {
 	//从控制台上输入的用户名和密码
 	public static void main(String[] args) {
 		Scanner sc = new Scanner(System.in);
 		System.out.println("请输入用户名:");
 		String name = sc.nextLine();
 		System.out.println("请输入密码:");
 		String password = sc.nextLine();
 		login(name, password);
 	}
 /**
 * 登录的方法
 */
 	public static void login(String name, String password) {
 		//a) 通过工具类得到连接
 		Connection connection = null;
 		Statement statement = null;
 		ResultSet rs = null;
 		try {
 			connection = JdbcUtils.getConnection();
 			//b) 创建语句对象,使用拼接字符串的方式生成 SQL 语句
 			statement = connection.createStatement();
 			//c) 查询数据库,如果有记录则表示登录成功,否则登录失败
			 String sql = "select * from user where name='" + name + "' and password='" + password
+ "'";
 			System.out.println(sql);
 			rs = statement.executeQuery(sql);
 			if (rs.next()) {
 				System.out.println("登录成功,欢迎您:" + name);
 			} else {
 				System.out.println("登录失败");
			 }
 			} catch (SQLException e) {
				 e.printStackTrace();
 			} finally {
 			//d) 释放资源
 				JdbcUtils.close(connection, statement, rs);
			 }
 	} 
 }

7.3.3 SQL 注入问题
当我们输入以下密码,我们发现我们账号和密码都不对竟然登录成功了

请输入用户名:
newboy
请输入密码:
a' or '1'='1
select * from user where name='newboy' and password='a' or '1'='1'
登录成功,欢迎您:newboy

问题分析:

select * from user where name='newboy' and password='a' or '1'='1'
   name='newboy' and password='a' 为假
   '1'='1' 真
   相当于
   select * from user where true; 查询了所有记录

我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了
原有 SQL 真正的意义,以上问题称为 SQL 注入。要解决 SQL 注入就不能让用户输入的密码和我们的 SQL 语句进
行简单的字符串拼接

第8节 PreparedStatement 接口

8.1 继承结构与作用:

在这里插入图片描述
PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句

8.2 PreparedSatement 的执行原理

在这里插入图片描述

  1. 因为有预先编译的功能,提高 SQL 的执行效率。
  2. 可以有效的防止 SQL 注入的问题,安全性更高。

8.3 Connection 创建 PreparedStatement 对象

在这里插入图片描述

8.4 PreparedStatement 接口中的方法:

在这里插入图片描述

8.5 PreparedSatement 的好处

  1. prepareStatement()会先将 SQL 语句发送给数据库预编译。PreparedStatement 会引用着预编译后的结果。
    可以多次传入不同的参数给 PreparedStatement 对象并执行。减少 SQL 编译次数,提高效率。
  2. 安全性更高,没有 SQL 注入的隐患
  3. 提高了程序的可读性

8.6 使用 PreparedStatement 的步骤:

  1. 编写 SQL 语句,未知内容使用?占位:"SELECT * FROM user WHERE name=? AND password=?";
  2. 获得 PreparedStatement 对象
  3. 设置实际参数:setXxx(占位符的位置, 真实的值)
  4. 执行参数化 SQL 语句
  5. 关闭资源

在这里插入图片描述
使用 PreparedStatement 改写上面的登录程序,看有没有 SQL 注入的情况

package com.itheima;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
/**
* 使用 PreparedStatement
*/
public class Demo8Login {
 	//从控制台上输入的用户名和密码
 	public static void main(String[] args) throws SQLException {
 		Scanner sc = new Scanner(System.in);
 		System.out.println("请输入用户名:");
 		String name = sc.nextLine();
 		System.out.println("请输入密码:");
 		String password = sc.nextLine();
 		login(name, password);
 	}
 /**
 * 登录的方法
 * @param name
 * 
 * * @param password
 */
 	private static void login(String name, String password) throws SQLException {
 		Connection connection = JdbcUtils.getConnection();
 		//写成登录 SQL 语句,没有单引号
 		String sql = "select * from user where name=? and password=?";
		//得到语句对象
 		PreparedStatement ps = connection.prepareStatement(sql);
 		//设置参数
 		ps.setString(1, name);
 		ps.setString(2,password);
 		ResultSet resultSet = ps.executeQuery();
 		if (resultSet.next()) {
 			System.out.println("登录成功:" + name);
 		}
 		else {
		 System.out.println("登录失败");
		 }
		 //释放资源,子接口直接给父接口
 		JdbcUtils.close(connection,ps,resultSet);
 } }

8.7 表与类的关系

在这里插入图片描述

  • 8.7.1 案例:使用 PreparedStatement 查询一条数据,封装成一个学生 Student 对象
package com.itheima;
import com.itheima.entity.Student;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Demo9Student {
 	public static void main(String[] args) throws SQLException {
 	//创建学生对象
 	Student student = new Student();
 	Connection connection = JdbcUtils.getConnection();
 	PreparedStatement ps = connection.prepareStatement("select * from student where id=?");
 	//设置参数
 	ps.setInt(1,2);
 	ResultSet resultSet = ps.executeQuery();
 	if (resultSet.next()) {
 		//封装成一个学生对象
		 student.setId(resultSet.getInt("id"));
 		student.setName(resultSet.getString("name"));
 		student.setGender(resultSet.getBoolean("gender"));
 		student.setBirthday(resultSet.getDate("birthday"));
 	}
 //释放资源
 JdbcUtils.close(connection,ps,resultSet);
 //可以数据
 System.out.println(student);
 } }

8.7.2 案例:将多条记录封装成集合 List,集合中每个元素是一个 JavaBean 实体类

 需求: 查询所有的学生类,封装成 List返回
 代码:

在这里插入图片描述

package com.itheima;
import com.itheima.entity.Student;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Demo10List {
 	public static void main(String[] args) throws SQLException {
 		//创建一个集合
 		List<Student> students = new ArrayList<>();
 		Connection connection = JdbcUtils.getConnection();
 		PreparedStatement ps = connection.prepareStatement("select * from student");
 		//没有参数替换
 		ResultSet resultSet = ps.executeQuery();
 		while(resultSet.next()) {
 			//每次循环是一个学生对象
 			Student student = new Student();
 			//封装成一个学生对象
 			student.setId(resultSet.getInt("id"));
 			student.setName(resultSet.getString("name"));
 			student.setGender(resultSet.getBoolean("gender"));
 			student.setBirthday(resultSet.getDate("birthday"));
 			//把数据放到集合中
 			students.add(student);
 		}
 		//关闭连接
 		JdbcUtils.close(connection,ps,resultSet);
 		//使用数据
 		for (Student stu: students) {
 			System.out.println(stu);
 		}
 	} 
}

8.8 PreparedStatement 执行 DML 操作

package com.itheima;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo11DML {
 	public static void main(String[] args) throws SQLException {
 	//insert();
	 //update();
 	delete();
 }
 	//插入记录
 private static void insert() throws SQLException {
 	 Connection connection = JdbcUtils.getConnection();
	 PreparedStatement ps = connection.prepareStatement("insert into 		student values(null,?,?,?)");
	 ps.setString(1,"小白龙");
	 ps.setBoolean(2, true);
 	 ps.setDate(3,java.sql.Date.valueOf("1999-11-11"));
     int row = ps.executeUpdate();
 	 System.out.println("插入了" + row + "条记录");
 	 JdbcUtils.close(connection,ps);
 }
 //更新记录: 换名字和生日
 private static void update() throws SQLException {
	Connection connection = JdbcUtils.getConnection();
 	PreparedStatement ps = connection.prepareStatement("update student set name=?, birthday=? where id=?");
 	ps.setString(1,"黑熊怪");
	 ps.setDate(2,java.sql.Date.valueOf("1999-03-23"));
 	ps.setInt(3,5);
 	int row = ps.executeUpdate();
 	System.out.println("更新" + row + "条记录");
 	JdbcUtils.close(connection,ps);
 }
 //删除记录: 删除第 5 条记录
 	private static void delete() throws SQLException {
 		Connection connection = JdbcUtils.getConnection();
 		PreparedStatement ps = connection.prepareStatement("delete from student where id=?");
		ps.setInt(1,5);
 		int row = ps.executeUpdate();
 		System.out.println("删除了" + row + "条记录");
 		JdbcUtils.close(connection,ps);
 	} 
 }

第9节 JDBC 事务的处理

之前我们是使用 MySQL 的命令来操作事务。接下来我们使用 JDBC 来操作银行转账的事务。

9.1 准备数据

CREATE TABLE account (
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(10),
	balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('Jack', 1000),
 ('Rose', 1000);

9.2 API 介绍

在这里插入图片描述

9.3 开发步骤

  1. 获取连接
  2. 开启事务
  3. 获取到 PreparedStatement
  4. 使用 PreparedStatement 执行两次更新操作
  5. 正常情况下提交事务
  6. 出现异常回滚事务
  7. 最后关闭资源
package com.itheima;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo12Transaction {
 	//没有异常,提交事务,出现异常回滚事务
 	public static void main(String[] args) {
		 //1) 注册驱动
 		Connection connection = null;
 		PreparedStatement ps = null;
 		try {
	 		//2) 获取连接
 			connection = JdbcUtils.getConnection();
 			//3) 开启事务
 			connection.setAutoCommit(false);
 			//4) 获取到 PreparedStatement
 			//从 jack 扣钱
			ps = connection.prepareStatement("update account set balance = balance - ? where name=?");
 			ps.setInt(1, 500);
			ps.setString(2,"Jack");
			ps.executeUpdate();
 			//出现异常
 			System.out.println(100 / 0);
 			//给 rose 加钱
 			ps = connection.prepareStatement("update account set balance = balance + ? where name=?");
 			ps.setInt(1, 500);
			ps.setString(2,"Rose");
 			ps.executeUpdate();
 			//提交事务
 			connection.commit();
 			System.out.println("转账成功");
 	} catch (Exception e) {
			 e.printStackTrace();
	try {
 		//事务的回滚
 		connection.rollback();
 	} catch (SQLException e1) {
 		e1.printStackTrace();
 	}
	 System.out.println("转账失败");
 	}
 	finally {
 	//7) 关闭资源
 		JdbcUtils.close(connection,ps);
 	}
} 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值