MyBatis(二)—— 入门程序之单表增删查改

1.数据准备

  1. mysql中创建一个名为mybatis的数据库;
  2. 导入table.sql创建数据表(本例中使用的是MySQL5.7,这个sql文件其他版本可能不适用)
-- MySQL dump 10.13  Distrib 5.7.17, for Win64 (x86_64)
--
-- Host: localhost    Database: mybatis
-- ------------------------------------------------------
-- Server version	5.7.19-log

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `items`
--

DROP TABLE IF EXISTS `items`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  `price` float(10,1) NOT NULL,
  `detail` text,
  `pic` varchar(64) DEFAULT NULL,
  `createtime` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `orderdetail`
--

DROP TABLE IF EXISTS `orderdetail`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `orderdetail` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `orders_id` int(11) NOT NULL,
  `items_id` int(11) NOT NULL,
  `items_num` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_orderdetail_1` (`orders_id`),
  KEY `FK_orderdetail_2` (`items_id`),
  CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `orders`
--

DROP TABLE IF EXISTS `orders`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `number` varchar(32) NOT NULL,
  `createtime` datetime NOT NULL,
  `note` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_orders_1` (`user_id`),
  CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `user`
--

DROP TABLE IF EXISTS `user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL,
  `birthday` date DEFAULT NULL,
  `sex` char(1) DEFAULT NULL,
  `address` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2020-07-25 14:03:26

  1. 导入data.sql创建初始数据
-- MySQL dump 10.13  Distrib 5.7.17, for Win64 (x86_64)
--
-- Host: localhost    Database: mybatis
-- ------------------------------------------------------
-- Server version	5.7.19-log

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Dumping data for table `items`
--

LOCK TABLES `items` WRITE;
/*!40000 ALTER TABLE `items` DISABLE KEYS */;
INSERT INTO `items` VALUES (1,'Computer',3000.0,'This computer is nice',NULL,'2020-07-23 13:22:53'),(2,'Laptop',6000.0,'This Laptop is nice',NULL,'2020-07-23 13:22:57'),(3,'Bag',200.0,'This bag is nice',NULL,'2020-07-23 13:23:02');
/*!40000 ALTER TABLE `items` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Dumping data for table `orderdetail`
--

LOCK TABLES `orderdetail` WRITE;
/*!40000 ALTER TABLE `orderdetail` DISABLE KEYS */;
INSERT INTO `orderdetail` VALUES (1,3,1,1),(2,3,2,3),(3,4,3,4),(4,4,2,3);
/*!40000 ALTER TABLE `orderdetail` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Dumping data for table `orders`
--

LOCK TABLES `orders` WRITE;
/*!40000 ALTER TABLE `orders` DISABLE KEYS */;
INSERT INTO `orders` VALUES (3,1,'1000010','2020-07-23 13:22:35',NULL),(4,1,'1000011','2020-07-23 13:22:41',NULL),(5,10,'1000012','2020-07-23 16:13:23',NULL);
/*!40000 ALTER TABLE `orders` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Dumping data for table `user`
--

LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES (1,'Wang Wu',NULL,'2',NULL),(10,'Zhang San','1990-07-10','1','BeiJing'),(16,'Li Si',NULL,'1','ShangHai'),(22,'Chen Xiaoming',NULL,'1','XinJiang'),(24,'Zhang Sanfeng',NULL,'1','HaErBin'),(25,'Chen Xiaomi',NULL,'1','GuangXi'),(26,'Wang Wu',NULL,NULL,NULL);
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2020-07-25 14:04:44

经历上述步骤,如果没有出现问题的话,用于测试的初始环境就算是创建完成了。

2. 入门程序

2.1 根据ID查询用户

1. 数据库配置文件db.properties。本例中,创建了一个名为config源文件夹(Source Folder),文件放在该目录下,后续配置文件除了特别说明外都放在该目录下

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.name=root
jdbc.password=root

2. log4j.properties

# Global logging configuration

log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#这里的输出格式可以根据需要自定义
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

3. 创建POJO类(简单JAVA对象,用来映射结果集)POJO类中的字段要与数据表中的列名相对应,并需要有getter/setter方法。下图为用户表的列名。

在这里插入图片描述

import java.util.Date;
public class User {
	private int id;
	private String sex;
	private String username;
	private Date birthday;
	private String address;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getSex() {
		return sex;
	}

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

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", sex=" + sex + ", username=" + username
				+ ", birthday=" + birthday + ", address=" + address + "]";
	}
}

4. 映射文件User.xml。本例中该文件放于config/sqlmap文件夹中,前面提到config文件夹是一个源文件夹

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- 通过id查询用户 -->
<mapper namespace="test">
	<select id="findUserById" parameterType="int" resultType="com.shao.pojo.User">
		SELECT * FROM USER WHERE id=#{id}
	</select>
</mapper>

映射文件为xml格式,整个xml实质内容都在<mapper></mapper>中,namespace指定命名空间,与下面的id一起,用于指定具体的映射块。因为本例中属于查询,所以映射块用<select></select>括起来。parameterType 指定入参类型,resultType指定出参类型,本例中直接映射成POJO类。

<select></select>之间放的是sql语句,id=#{id}#{}表示占位符,在使用时,实参将被传递到这里代替占位符。这样,一个简单的映射文件就形成了。

sql语句,出入参类型都写到配置文件里面去了,解决了JDBC 中硬编码的问题。

5. MyBatis的全局配置文件SqlMapConfig.xml

<?xml version="1.0"  encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 数据库配置文件 -->
<properties resource="db.properties" />
<!-- 默认是development环境 -->
	<environments default="development">
		<environment id="development">
			<!-- 事务管理使用JDBC,事务控制由mybatis来负责 -->
			<transactionManager type="JDBC" />
			<!-- 数据库连接池,由mybatis管理 -->
			<dataSource type="POOLED">
				<!-- 从数据库配置文件中读取数据库参数 -->
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.name}" />
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>
	<!-- 在这里配置映射文件,本例中为放在config目录下的sqlmap/User.xml,因为config是源文件夹,所以不用写 -->
	<mappers>
		<mapper resource="sqlmap/User.xml" />
	</mappers>
</configuration>

SqlMapConfig.xmlMyBatis的全局配置文件,可以说还是比较重要,后面会有单独的章节对里面的参数配置进行说明。因为是入门程序,所以这里先不展开。

配置文件中配置了数据库连接池(这里面没有配置长连接数量、最大连接数量等参数),一定程度上解决了JDBC 用就打开不用就关闭带来的数据库性能问题。

6. 测试。本例用了JUnit 4

@Test
	public void testFindUserById() {
		try {
		   // 读取全局配置文件
			String resource = "SqlMapConfig.xml";
			InputStream inputStream = Resources.getResourceAsStream(resource);
			//框架中的会话工厂
			SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
					.build(inputStream);
			//由会话工厂创建会话,通过会话具体操作数据库
			SqlSession sqlSession = sessionFactory.openSession();
			//因为只查询一条,所以用selectOne,传了两个实参,一个实参是“命名空间.id”用于匹配映射文件中的具体内容,另一个是传递到sql语句中代替占位符的实际量。
			User user = sqlSession.selectOne("test.findUserById", 10);
			System.out.println(user);
			sqlSession.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

输出如下(截取部分)。因为我们在映射文件中要求出参类型是POJO型,所以我们可以看到User [id=10, sex=1, username=Zhang San, birthday=Tue Jul 10 00:00:00 CDT 1990, address=BeiJing]已经映射成了POJO型。这从一定程度上解决了JDBC ResultSet结果集获取数据比较麻烦的事情。
在这里插入图片描述

2.2 根据名称模糊查询用户

这里的名称,指的是MySQL表里面的username。根据名称模糊查询,用到的是sql语句中的‘like’关键字。

需要注意的是,模糊查询,可能会查询到多条记录,所以结果不再是单条记录,我们需要用一个List来保存结果。

基本的环境和代码条件前一步都已经具备了,这里只需要在映射文件中加一点内容,然后再写一个测试程序就行了。

1. 映射文件User.xml中添加以下内容(在<mapper></mapper>中添加,与前面一段映射块平级)

<!-- 通过用户名模糊查询 -->
<select id="findUserByName" parameterType="java.lang.String"
		resultType="com.shao.pojo.User">
	SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>

需要注意两点:
(1)这里,resultType还是POJO类而不是List
(2)${}表示拼接字符串,将接收到的参数不加修饰的拼接到sql语句中,使用该方式拼接sql语句,会引起sql注入;另外,当传入的是简单类型是,sql语句中${}里放的只能是value,试着将单词value修改为其它时,程序将无法运行。

2. 测试程序

	/**
	 * 通过用户名模糊查询
	 */
	@Test
	public void findUserByNameTest(){
		try {
			String resource = "SqlMapConfig.xml";
			InputStream inputStream = Resources.getResourceAsStream(resource);
			SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
					.build(inputStream);
			SqlSession sqlSession = sessionFactory.openSession();
			List<User> list=sqlSession.selectList("test.findUserByName", "Zhang");
			System.out.println(list);
			sqlSession.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

这里也需要注意两点:
(1)可以看到会有代码重复,但是这里只是入门程序,后面会专门说到会话工厂和会话的使用范围,这里不过多强调;
(2)因为查询结果可能存在多条,所以用的是List来接受结果,用resultType中定义的POJO类(也就是User)来限定List中存储的类型,然后用selectList来代替了前一章节中的selectOne。这里再次强调,不管是selectOne还是selectList还是接下来的增、删、改,都需要注意,传入的参数一定和映射文件中namespace.id能对应上

来看一下输出(截取部分):
在这里插入图片描述
从输出结果看,测试程序中传入的“Zhang”确实是拼接到sql语句中去了,查出来的结果也不止一条,证明程序能正常运行。

2.3 添加用户

该说的前面都说的差不多了,这里就不赘述了,直接看映射文件中的配置和测试程序吧。

1. 映射文件(User.xml)中添加

<insert id="insertUser" parameterType="com.shao.pojo.User">
		INSERT INTO
		USER(username,sex,birthday,address)
		VALUE(#{username},#{sex},#{birthday},#{address})
		<!-- 主键返回 -->
		<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
			<!-- 适用于自增主键 -->
			SELECT LAST_INSERT_ID()
		</selectKey>
	</insert>

这里要注意,因为数据表中,用户id被设置为自增,所以插入时就不需要指定id了。另外,由于是id为主键且自增,当有需要时,可以通过嵌套<selectKey>标签获取自增主键,相关的sql语句为SELECT LAST_INSERT_ID()。当不嵌套<selectKey>标签时自增主键返回默认值。

keyProperty对应的是自增主键在MYSQL表中的字段名order指定SELECT LAST_INSERT_ID()相对insert语句的执行顺序。

2. 测试程序

	/**
	 * 插入新用户
	 */
	@Test
	public void insertUserTest(){
		try {
			String resource = "SqlMapConfig.xml";
			InputStream inputStream = Resources.getResourceAsStream(resource);
			SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
			.build(inputStream);
			SqlSession sqlSession = sessionFactory.openSession();
			User user=new User();
			//或者也可以使用POJO中的setter赋值,当属性比较多比较复杂的时候,也可以考虑使用建造者模式
			user.setUsername("Li Xiaopeng");
			user.setSex("2");
			user.setBirthday(Date.from(LocalDate.of(1999, 1, 9).atStartOfDay(ZoneId.systemDefault()).toInstant()));
			user.setAddress("Shanghai");
			sqlSession.insert("test.insertUser", user);
			sqlSession.commit();
			//在自增主键的情况下User.xml必须指定selectType类型,否则查询不到
			System.out.println("--------------------" + user.getId() + "--------------------");
			sqlSession.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

需要注意一下:

增、删、改操作都需要调用sqlSession.commit();进行手动提交。

来看一下输出(截取部分):
在这里插入图片描述
从输出结果看,已经插入成功,而且自增的主键也获取到了。、

下面是MySQL中数据表中的数据,可以看到最后一条记录就是刚刚插入的。
在这里插入图片描述
3. 补充一个小知识

当主键为非自增并需要返回时,可以使用MySQLuuid()函数,使用这个函数的前提是:将主键的字段类型设置为字符串类型,并且长度设置为35位uuid产生的是字符串类型值,固定长度为36个字符。先通过uuid()函数查询到主键,再返回到sql语句中。

需要注意的是,使用uuid()时,相对于insert语句的指向顺序是“BEFORE”,同时,因为主键不是自增,所以理所应当的,insert语句中要插入主键。
在这里插入图片描述

2.4 删除用户

1. 映射文件(User.xml

删除就简单了,因为删除没有什么可返回的,所以只需要定义id和入参类型即可。

	<!-- 删除用户 -->
	<delete id="deleteUser" parameterType="java.lang.Integer">
		delete from user where id=#{id}
	</delete>

2. 测试程序

@Test
	public void deleteUserTest(){
		try {
			String resource = "SqlMapConfig.xml";
			InputStream inputStream = Resources.getResourceAsStream(resource);
			SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
			.build(inputStream);
			SqlSession sqlSession = sessionFactory.openSession();
			sqlSession.delete("test.deleteUser", 30);
			sqlSession.commit();
			sqlSession.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

把刚才刚插入的一条新纪录给删了,下面的数据表说明,已经删除成功了。
在这里插入图片描述

再来看看输出好了(截取部分):
在这里插入图片描述

2.5 更新用户信息

1. 映射文件(User.xml)

	<update id="updateUser" parameterType="com.shao.pojo.User">
		update user set username=#{username} where id=#{id}
	</update>

需要改什么就在sql语句中添加相关的字段即可,本例中只是修改用户名。

2. 测试程序

@Test
	public void updateUserTest(){
		try {
			String resource = "SqlMapConfig.xml";
			InputStream inputStream = Resources.getResourceAsStream(resource);
			SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
			.build(inputStream);
			SqlSession sqlSession = sessionFactory.openSession();
			User user=new User();
			user.setId(22);
			user.setUsername("Test Update");
			sqlSession.update("test.updateUser", user);
			sqlSession.commit();
			sqlSession.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

需要注意:因为是根据id来对数据进行修改,所以id字段是必须要存在的。更新用户时,可以新建一个用户对象,设置好id后,设置需要修改的字段并插入(没有设置的字段会保持不变);也可以在已有对象的基础上进行克隆操作(注意浅克隆和深克隆的区分)之后插入。

可以看到数据表中相关的信息已经被修改了。
在这里插入图片描述

再来看看截取的部分输出内容:

在这里插入图片描述

2.6 工程结构

还是把工程结构放这儿。(#)表示Source Folder

在这里插入图片描述
有几个包是后面才用到的,为了不引起误导,先屏蔽掉。

3. 总结

本文主要介绍了MyBatis的几个简单的入门程序。用的环境是MySQL5.7MyBatis 3.4.4。从程序中也可以看出来,MyBatis确实解决了上一文中提到的若干问题,编程的主要关键点还是在配置文件中,可见配置文件在MyBatis编程中中还是很重要的。

需要注意的一些细节问题在文中各处也都说了,限于篇幅,这里不赘述。

4. 参考文献

【1】 MyBatis User Guide
【2】传智 “SpringMVC+MyBatis由浅入深”教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值