javaWeb基础07-jdbc

案例1-通过jdbc完成单表的curd操作

jdbc:

java操作数据库.jdbc是oracle公司指定的一套规范(一套接口)
驱动:jdbc的实现类.由数据库厂商提供.
我们就可以通过一套规范操作不同的数据库了(多态)
jdbc作用:
	连接数据库
	发送sql语句
	处理结果

jdbc操作步骤:★

1.数据库和表
2.创建一个项目
3.导入驱动jar包
4.编码:
	注册驱动
	获取连接
	编写sql
	创建预编译的语句执行者
	设置参数
	执行sql
	处理结果
	释放资源

初始化数据库和表:
CREATE DATABASE day07;
USE day07;	

create table category(
	cid varchar(20) primary key,
	cname varchar(20)
);

insert into category values('c001','电器');
insert into category values('c002','服饰');
insert into category values('c003','化妆品');
insert into category values('c004','书籍');
IDE打开之后
	1.修改字符集 utf-8
	2.新建 java项目
	3.使用的jdk为自己的jdk 不用使用内置

使用junit单元测试
	要求:
		1.方法是public void xxx(){}
		2.在方法上添加 @Test
		3.在@Test 按下 ctrl+1(快速锁定错误)
		4.在方法上右键 run as  -->junit 就可以执行方法了.

jdbc-api详解:

所有的包 都是 java.sql 或者 javax.sql

DriverManager:管理了一组jdbc的操作 类
	常用方法:
		了解:注册驱动	
			static void registerDriver(Driver driver) :
				通过查看 com.mysql.jdbc.Driver的源码 有如下代码
 static {
	try {
		java.sql.DriverManager.registerDriver(new Driver());//这段代码我们已经写过
	} catch (SQLException E) {
		throw new RuntimeException("Can't register driver!");
	}
}
				驱动注册了两次.我们只需要将静态代码块执行一次,类被加载到内存中会执行静态代码块,并且只执行一次.
				现在只需要将类加载到内存中即可:
					方式1:
						★Class.forName("全限定名");//包名+类名   com.mysql.jdbc.Driver
					方式2:
						类名.class;
					方式3:
						对象.getClass();

		掌握:获取连接
			static Connection getConnection(String url, String user, String password) 
				参数1:告诉我们连接什么类型的数据库及连接那个数据库
							协议:数据库类型:子协议 参数
					mysql:	jdbc:mysql://localhost:3306/数据库名称
					oracle:	jdbc:oracle:thin@localhost:1521@实例
					
				参数2:账户名 root
				参数3:密码


(了解)Driver:java.sql 接口 驱动
Connection:连接 接口
	常用方法:
		获取语句执行者:
			(了解)Statement createStatement() :获取普通的语句执行者  会出现sql注入问题
			★PreparedStatement prepareStatement(String sql) :获取预编译语句执行者
			(了解)CallableStatement prepareCall(String sql):获取调用存储过程的语句执行者

		了解:
			setAutoCommit(false) :手动开启事务
			commit():提交事务
			rollback():事务回滚

Statement:语句执行者 接口
PreparedStatement:预编译语句执行者 接口
	常用方法:
		设置参数:
			setXxx(int 第几个问号,Object 实际参数);
				常见的方法:
					 setInt
					 setString
					 setObject
		
		执行sql:
			 ResultSet executeQuery() :执行 r 语句 返回值:结果集
			 int executeUpdate() :执行cud 语句 返回值:影响的行数


ResultSet:结果集 接口
	执行查询语句之后返回的结果
		常用方法:
			boolean next():判断是否有下一条记录,若有返回true且将光标移到下一行,若没有呢则返回false
				光标一开始处于第一条记录的上面
			
			获取具体内容
				getXxx(int|string)
					若参数为int :第几列
					若参数为string:列名(字段名)
				例如:
					获取cname的内容可以通过
						getString(2)
						getString("cname")
				常用方法:
					getInt
					getString 也可以获取int值
					getObject 可以获取任意

常见的配置文件格式:

1.properties
	里面内容的格式 key=value
2.xml
若我们的配置文件为properties,并且放在src目录下.
我们可以通过 ResourceBundle工具快速获取里面的配置信息
	使用步骤:
		1.获取ResourceBundle 对象:
			static ResourceBundle getBundle("文件名称不带后缀名") 
		2.通过ResourceBundle 对象获取配置信息 
			String getString(String key) :通过执行key获取指定的value

案例

@Test
public void test2() throws Exception {
	//注册驱动
	//DriverManager.registerDriver(new Driver());
	//为什么不用DriverManager.registerDriver(new Driver());?因为Driver内部又注册了一次。
	Class.forName("com.mysql.jdbc.Driver");
	
	
	//获取连接 
	Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day07", "root", "123456");
	//创建执行语句预编译对象
	PreparedStatement ps = conn.prepareStatement("select * from category");
	//设置参数
	//执行sql,获取结果集
	ResultSet rs = ps.executeQuery();
	while (rs.next()) {
		String cid = rs.getString("cid");
		String cname = rs.getString("cname");
		System.out.println("test2---cid="+cid+",cname="+cname);
	}
	//释放资源:关闭connection resultset ps
	rs.close();
	ps.close();
	conn.close();
}

封装 注册驱动+获取连接 和释放资源的操作:

@Test
public void test3() throws Exception {
	//注册驱动 +获取连接 
	Connection conn = Jdbc1Utils.getConnection();
	//创建执行语句预编译对象
	PreparedStatement ps = conn.prepareStatement("select * from category");
	//设置参数
	//执行sql,获取结果集
	ResultSet rs = ps.executeQuery();
	while (rs.next()) {
		String cid = rs.getString("cid");
		String cname = rs.getString("cname");
		System.out.println("test3---cid="+cid+",cname="+cname);
	}
	//释放资源:关闭connection resultset ps
	Jdbc1Utils.closeResource(rs, ps, conn);
}
public class Jdbc1Utils {

	public static Connection getConnection() throws Exception {
		//注册驱动
		Class.forName("com.mysql.jdbc.Driver");
		
		//获取连接 
		Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day07", "root", "123456");
		return conn;
	}
	
	public static void closeResource(ResultSet rs,Statement st,Connection conn) {
		closeResultSet(rs);
		closeStatement(st);
		closeConnection(conn);
	}
	
	
	public static void closeResultSet(ResultSet rs) {
		if(null!=rs) {
			try {
				rs.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			rs=null;
		}
	}
	
	public static void closeStatement(Statement st) {
		if(null!=st) {
			try {
				st.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			st=null;
		}
	}
	
	public static void closeConnection(Connection conn) {
		if(null!=conn) {
			try {
				conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			conn=null;
		}
	}
}

优化: 数据库的信息我们应该写到配置文件里面,这样改的话比较方便

@Test
public void test4() throws Exception {
	Connection conn = JdbcUtils.getConnection();
	//创建执行语句预编译对象
	PreparedStatement ps = conn.prepareStatement("select * from category");
	//设置参数
	//执行sql,获取结果集
	ResultSet rs = ps.executeQuery();
	while (rs.next()) {
		String cid = rs.getString("cid");
		String cname = rs.getString("cname");
		System.out.println("test4---cid="+cid+",cname="+cname);
	}
	//释放资源:关闭connection resultset ps
	JdbcUtils.closeResource(rs, ps, conn);
}
public class JdbcUtils {
	
	public static final String DRIVERCLASS;
	public static final String URL;
	public static final String USER;
	public static final String PASSWORD;
	
	//jdbc
//	static {
//		ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
//		DRIVERCLASS = bundle.getString("driverClass");
//		URL = bundle.getString("url");
//		USER = bundle.getString("user");
//		PASSWORD = bundle.getString("password");
//	}

	//c3p0	
//	static {
//		ResourceBundle bundle = ResourceBundle.getBundle("c3p0");
//		DRIVERCLASS = bundle.getString("c3p0.driverClass");
//		URL = bundle.getString("c3p0.jdbcUrl");
//		USER = bundle.getString("c3p0.user");
//		PASSWORD = bundle.getString("c3p0.password");
//	}

	//dbcp	
	static {
		ResourceBundle bundle = ResourceBundle.getBundle("dbcp");
		DRIVERCLASS = bundle.getString("driverClassName");
		URL = bundle.getString("url");
		USER = bundle.getString("username");
		PASSWORD = bundle.getString("password");
	}	
	static {
		//注册驱动
		try {
			Class.forName(DRIVERCLASS);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static Connection getConnection() throws Exception {
		//获取连接 
		Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
		return conn;
	}
	
	public static void closeResource(ResultSet rs,Statement st,Connection conn) {
		closeResultSet(rs);
		closeStatement(st);
		closeConnection(conn);
	}
	
	
	public static void closeResultSet(ResultSet rs) {
		if(null!=rs) {
			try {
				rs.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			rs=null;
		}
	}
	
	public static void closeStatement(Statement st) {
		if(null!=st) {
			try {
				st.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			st=null;
		}
	}
	
	public static void closeConnection(Connection conn) {
		if(null!=conn) {
			try {
				conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			conn=null;
		}
	}
}

增:

@Test
public void test5() throws Exception {
	Connection conn = JdbcUtils.getConnection();
	//创建执行语句预编译对象
	PreparedStatement ps = conn.prepareStatement("insert into category values(?,?)");
	//设置参数
	ps.setObject(1, "c007");
	ps.setString(2, "小米手机");
	int executeUpdate = ps.executeUpdate();
	System.out.println("test5---executeUpdate="+executeUpdate);
	//释放资源:关闭connection resultset ps
	JdbcUtils.closeResource(null, ps, conn);
}

改:

@Test
public void test6() throws Exception {
	Connection conn = JdbcUtils.getConnection();
	//创建执行语句预编译对象
	PreparedStatement ps = conn.prepareStatement("update category set cname=? where cid=?");
	//设置参数
	ps.setObject(1, "小米9");
	ps.setString(2, "c008");
	int executeUpdate = ps.executeUpdate();
	System.out.println("test6---executeUpdate="+executeUpdate);
	//释放资源:关闭connection resultset ps
	JdbcUtils.closeResource(null, ps, conn);
}

删:

@Test
public void f7() throws Exception {
	//获取连接
	Connection conn = JdbcUtils.getConnection();
	//语句执行者
	PreparedStatement ps = conn.prepareStatement("delete from category where cid=?");
	//执行
	ps.setString(1, "c007");
	int executeUpdate = ps.executeUpdate();
	System.out.println("test7---executeUpdate="+executeUpdate);
	//释放资源
	//释放资源:关闭connection resultset ps
	JdbcUtils.closeResource(null, ps, conn);
}

案例2-通过连接池(数据源)优化我们的操作.

需求:

使用jdbc的时候,没操作一次都需要获取连接(创建)用完之后把连接释放掉了(销毁),通过连接池来优化curd操作.

技术分析:

连接池

连接池概述:

管理数据库的连接,
作用:
	提高项目的性能.
就是在连接池初始化的时候存入一定数量的连接,用的时候通过方法获取,不用的时候归还连接即可.
所有的连接池必须实现一个接口 javax.sql.DataSource接口

获取连接方法:
	Connection getConnection() 
归还连接的方法就是以前的释放资源的方法.调用connection.close();
自定义一个连接池(理解思想)

常用连接池:

DBCP
C3P0 

增强方法

1.继承
2.装饰者模式(静态代理)
3.动态代理

装饰者模式:★★★

使用步骤:
	1.装饰者和被装饰者实现同一个接口或者继承同一个类
	2.装饰者中要有被装饰者的引用
	3.对需要增强的方法进行加强
	4.对不需要加强的方法调用原来方法

常用的连接池:

DBCP:(理解)

	apache组织
	使用步骤:
		1.导入jar包(commons-dbcp-1.4.jar和commons-pool-1.5.6.jar)
		2.使用api
			a.硬编码
				//创建连接池
				BasicDataSource ds = new BasicDataSource();
				
				//配置信息
				ds.setDriverClassName("com.mysql.jdbc.Driver");
				ds.setUrl("jdbc:mysql:///day07");
				ds.setUsername("root");
				ds.setPassword("1234");
			b.配置文件
				实现编写一个properties文件
				//存放配置文件
				Properties prop = new Properties();
				prop.load(new FileInputStream("src/dbcp.properties"));
				//设置
				//prop.setProperty("driverClassName", "com.mysql.jdbc.Driver");
				
				//创建连接池
				DataSource ds = new BasicDataSourceFactory().createDataSource(prop);

C3P0:(★)

	hibernate和spring使用
	有自动回收空闲连接的功能.
	使用步骤:
		1.导入jar包(c3p0-0.9.1.2.jar)
		2.使用api
			a.硬编码(不推荐)
				new ComboPooledDataSource()
			b.配置文件
				配置文件的名称:c3p0.properties 或者 c3p0-config.xml
				配置文件的路径:src下
			
				编码只需要一句话
					new ComboPooledDataSource()//使用默认的配置
					new ComboPooledDataSource(String configName)//使用命名的配置 若配置的名字找不到,使用默认的配置

自定义简易连接池

public static void main(String[] args) {
	MyDateSource ds = new MyDateSource();
	Connection conn = ds.getConnection();
//		Connection conn = MyDateSource.getConnection();
	System.out.println(conn);
	MyDateSource.addBack(conn);
}
public class MyDateSource {
	
	public static LinkedList<Connection> pooList=new LinkedList<Connection>();

	//创建3个连接,并放入集合中
	static {
		for (int i = 0; i < 3; i++) {
			try {
				Connection conn = JdbcUtils.getConnection();
				pooList.addLast(conn);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	
	//取任意一个连接
	public static Connection getConnection() {
		//取之前判断连接池是否为空,为空则新增3个
		if(pooList.isEmpty()) {
			for (int i = 0; i < 3; i++) {
				try {
					Connection conn = JdbcUtils.getConnection();
					pooList.addLast(conn);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return pooList.removeFirst();
	}
	//归还连接
	public static void addBack(Connection conn) {
		pooList.addLast(conn);
	}
}

Connection 装饰者模式+简易连接池(各连接池jar的原理)

Connection 装饰者模式:

public class ConnectionWrap implements Connection {
	
	private Connection conn;
	private LinkedList<Connection> list;
	public ConnectionWrap(Connection conn,LinkedList<Connection> list) {
		this.conn=conn;
		this.list=list;
	}

	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException {
		return conn.unwrap(iface);
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public Statement createStatement() throws SQLException {
		return conn.createStatement();
	}

	@Override
	public PreparedStatement prepareStatement(String sql) throws SQLException {
		return conn.prepareStatement(sql);
	}
	
	@Override
	public void close() throws SQLException {
		System.out.println("close前---"+list.size());
		list.addLast(this);
		System.out.println("close后---"+list.size());
	}
	...
}

自定义简易连接池:

public class MyDateSource {
	
	public static LinkedList<Connection> pooList=new LinkedList<Connection>();

	//创建3个连接,并放入集合中
	static {
		for (int i = 0; i < 3; i++) {
			try {
				Connection conn = JdbcUtils.getConnection();
				pooList.addLast(conn);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	
	//取任意一个连接
	public static Connection getConnection() {
		//取之前判断连接池是否为空,为空则新增3个
		if(pooList.isEmpty()) {
			for (int i = 0; i < 3; i++) {
				try {
					Connection conn = JdbcUtils.getConnection();
					pooList.addLast(conn);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		Connection conn = pooList.removeFirst();
		ConnectionWrap wrap = new  ConnectionWrap(conn, pooList);
		return wrap;
	}
	
	//归还连接
	public static void addBack(Connection conn) {
		pooList.addLast(conn);
	}
}

测试:

public static void main(String[] args) throws SQLException {
	MyDateSource ds = new MyDateSource();
	Connection conn = ds.getConnection();
	System.out.println(conn);
	conn.close();
}

dbcp连接池

在这里插入图片描述

  • 需要2个jar: commons-dbcp-1.4.jar+commons-pool-1.5.6.jar
@Test
public void f1() throws SQLException {
	//创建数据源
	BasicDataSource ds = new BasicDataSource();
	ds.setDriverClassName("com.mysql.jdbc.Driver");
	ds.setUrl("jdbc:mysql:///day07");
	ds.setUsername("root");
	ds.setPassword("123456");
	//获取连接
	Connection conn = ds.getConnection();
	PreparedStatement ps = conn.prepareStatement("insert into category values(?,?)");
	ps.setString(1, "c008");
	ps.setString(2, "苹果12");
	//执行
	int executeUpdate = ps.executeUpdate();
	JdbcUtils.closeResource(null, ps, conn);
}

@Test
public void f2() throws Exception {
	
	Properties properties=new Properties();
	properties.load(new FileInputStream("src/dbcp.properties"));
	//创建数据源
	DataSource ds = BasicDataSourceFactory.createDataSource(properties);
	
	//获取连接
	Connection conn = ds.getConnection();
	PreparedStatement ps = conn.prepareStatement("insert into category values(?,?)");
	ps.setString(1, "c009");
	ps.setString(2, "苹果13");
	//执行
	int executeUpdate = ps.executeUpdate();
	JdbcUtils.closeResource(null, ps, conn);
}

dbcp.properties:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///day07
username=root
password=123456

9

c3p0连接池

c3p0-0.9.1.2.jar

@Test
public void f1() throws Exception {
	ComboPooledDataSource ds=new ComboPooledDataSource();
	//如果默认是c3p0.properties,下面的4行可以省略
	ds.setDriverClass("com.mysql.jdbc.Driver");
	ds.setJdbcUrl("jdbc:mysql:///day07");
	ds.setUser("root");
	ds.setPassword("123456");
	//获取连接
	Connection conn = ds.getConnection();
	PreparedStatement ps = conn.prepareStatement("insert into category values(?,?)");
	ps.setString(1, "c010");
	ps.setString(2, "苹果10");
	//执行
	int executeUpdate = ps.executeUpdate();
	JdbcUtils.closeResource(null, ps, conn);
}

封装数据库参数:

@Test
public void f2() throws Exception {
	ComboPooledDataSource ds=new ComboPooledDataSource("c3p0.properties");

	//获取连接
	Connection conn = ds.getConnection();
	PreparedStatement ps = conn.prepareStatement("insert into category values(?,?)");
	ps.setString(1, "c011");
	ps.setString(2, "苹果11");
	//执行
	int executeUpdate = ps.executeUpdate();
	JdbcUtils.closeResource(null, ps, conn);
}

案例3-使用dbutils完成curd操作

dbutils:

是apache组织的一个工具类,jdbc的框架,更方便我们使用
使用步骤:
	1.导入jar包(commons-dbutils-1.4.jar)
	2.创建一个queryrunner类
		queryrunner作用:操作sql语句
			构造方法:
				new QueryRunner(Datasource ds);
	3.编写sql
	4.执行sql
		query(..):执行r操作
		update(...):执行cud操作

核心类或接口

QueryRunner:类名
	作用:操作sql语句
	构造器:
		new QueryRunner(Datasource ds);
	注意:
		底层帮我们创建连接,创建语句执行者 ,释放资源.
	常用方法:
		query(..):
		update(..):

DbUtils:释放资源,控制事务 类
	closeQuietly(conn):内部处理了异常
	commitAndClose(Connection conn):提交事务并释放连接
	....

ResultSetHandler:封装结果集 接口
	
	 ArrayHandler, ArrayListHandler, BeanHandler, BeanListHandler, ColumnListHandler, KeyedHandler, MapHandler, MapListHandler, ScalarHandler

带有List表示结果是集合,不带list表示结果是对象(相等于取集合的第一条数据)

 (了解)ArrayHandler, 将查询结果的第一条记录封装成数组,返回
 (了解)ArrayListHandler, 将查询结果的每一条记录封装成数组,将每一个数组放入list中返回
 ★★BeanHandler, 将查询结果的第一条记录封装成指定的bean对象,返回
 ★★BeanListHandler, 将查询结果的每一条记录封装成指定的bean对象,将每一个bean对象放入list中 返回.
 (了解)ColumnListHandler, 将查询结果的指定一列放入list中返回 
 (了解)MapHandler, 将查询结果的第一条记录封装成map,字段名作为key,值为value 返回
 ★MapListHandler, 将查询结果的每一条记录封装map集合,将每一个map集合放入list中返回
 ★ScalarHandler,针对于聚合函数 例如:count(*) 返回的是一个Long值

在这里插入图片描述

BeanHandler

QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
Category category = qr.query(sql, new BeanHandler<>(Category.class));
System.out.println(category);

在这里插入图片描述

BeanListHandler

QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
List<Category> list = qr.query(sql, new BeanListHandler<>(Category.class));
for (Category category : list) {
	System.out.println(category);
}

在这里插入图片描述

ScalarHandler

QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select count(cid) from category";
Object Object = qr.query(sql, new ScalarHandler());
System.out.println(Object.getClass().getName());
System.out.println(Object);
Long count = (Long) qr.query(sql, new ScalarHandler());
System.out.println(count);

在这里插入图片描述

ArrayHandler

QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
Object[] result = qr.query(sql, new ArrayHandler());
System.out.println(Arrays.toString(result))

在这里插入图片描述

ArrayListHandler

QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
List<Object[]> list = qr.query(sql, new ArrayListHandler());
for (Object[] objects : list) {
	System.out.println(Arrays.toString(objects));
}

在这里插入图片描述

MapHandler

QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
Map<String, Object> map = qr.query(sql, new MapHandler());
System.out.println(map);

在这里插入图片描述

MapListHandler

QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
List<Map<String,Object>> list = qr.query(sql, new MapListHandler());
for (Map<String,Object> map : list) {
	System.out.println(map);
}

在这里插入图片描述

ColumnListHandler

QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
//无参默认第一列的值
List<Object> list = qr.query(sql, new ColumnListHandler("cname"));
for (Object object : list) {
	System.out.println(object);
	System.out.println(object.getClass().getName());
}

在这里插入图片描述

KeyedHandler

QueryRunner qr = new QueryRunner(C3p0DataSourceUtils.getDataSource());
String sql="select * from category";
//无参默认第一列的值
Map<Object, Map<String, Object>> map = qr.query(sql, new KeyedHandler());
System.out.println(map);
Set<Object> keySet = map.keySet();
for (Object cid : keySet) {
	//key:cid   value:record
	System.out.println(cid+"---"+map.get(cid));
}

在这里插入图片描述

源码

JdbcDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值