Mybatis(一)

一、Mybatis

1、简介

MyBatis 是一款优秀的持久层框架;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

2、优点

1、简单易学

mybatis本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。  

2、灵活

mybatis不会对应用程序或者数据库的现有设计强加任何影响。sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。  

3、解除sql与程序代码的耦合

通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。 

4、提供映射标签,支持对象与数据库的orm字段关系映射  

5、提供对象关系映射标签,支持对象关系组建维护 

6、提供xml标签,支持编写动态sql。 

3、缺点

1、编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。  

2、SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。

3、框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。

4、二级缓存机制不佳。

二、Mybatis操作

创建数据库及数据表

1、Mybatis原生使用

pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.5.6</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.example</groupId>
   <artifactId>Mybatis_proto</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>Mybatis_proto</name>
   <description>Demo project for Spring Boot</description>
   <properties>
      <java.version>1.8</java.version>
   </properties>
<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>

   <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
   </dependency>
   <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
   <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.27</version>
   </dependency>

   <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
   <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.7</version>
   </dependency>

   <dependency>
      <groupId>com.example</groupId>
      <artifactId>mybatis</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <scope>compile</scope>
   </dependency>

</dependencies>
    <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
      <!-- 定义classpath -->
      <resources>
         <!-- resources文件 -->
         <resource>
            <directory>src/main/resources</directory>
            <!-- 是否被过滤,如果被过滤则无法使用 -->
            <filtering>false</filtering>
         </resource>
         <!-- java文件夹 -->
         <resource>
            <directory>src/main/java</directory>
            <!-- 引入映射文件等 -->
            <includes>
               <include>**/*.xml</include>
               <include>**/*.properties</include>
            </includes>
         </resource>
      </resources>
   </build>

</project>

写 SQL 的 mapper xml

<?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">
<mapper namespace="com.example.mybatis_proto.mapper.UserMapper">

    <select id="selectUser" resultType="com.example.mybatis_proto.entity.User" parameterType="com.example.mybatis_proto.entity.User">
        select * from springsemester where id = #{id}
    </select>

</mapper>

Mapper 接口类,结合使用了 @Select

/**
 * UserMapper 接口,映射对数据库的操作
 */
public interface UserMapper {

    public User selectUser(int id);
    
    @Select("select * from springsemester")
    public List<User>  selectAllUsers();
}

User实体类

/**
 * @author DF10F-0001A
 */
public class User {
    private int id;
    private String name;
    private int age;
    private String dapartment;

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

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

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

    public String getDapartment() {
        return dapartment;
    }

    public void setDapartment(String dapartment) {
        this.dapartment = dapartment;
    }
}

启动类MybatisProtoApplication

/**
 * 测试 Mybatis xml 与 注解的使用
 * @author DF10F-0001A
 */
public class MybatisProtoApplication {

    public static void main(String[] args) throws IOException {
        testJavaConfig();
    }
    
    /**
     * 测试 Java 方式
     */
    private static void testJavaConfig() {
        // 创建数据源
        DataSource dataSource = new PooledDataSource("com.mysql.jdbc.Driver",
                "jdbc:mysql://127.0.0.1:3306/springsemester?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8",
                "root",
                "123456");
        //事务
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        //环境
        Environment environment = new Environment("development", transactionFactory, dataSource);
        //配置
        Configuration configuration = new Configuration(environment);
        //注册
        configuration.addMapper(UserMapper.class);
        SqlSessio	nFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        //查询所有 user 数据
        List<User> users = userMapper.selectAllUsers();
        System.out.println(users);

        //关闭 SqlSession
        sqlSession.close();
    }
}

2、Mybatis开发方式

(1)、mapper代理对象 + xml

使用动态代理机制,dao层接口化,底层自动创建代理对象代替dao对象创建SqlSession,并且自动与xml文件进行sql配对。

UserDao.java

public class User implements Serializable {
    private int id;
    private String name;
    private int age;
    private String dapartment;

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

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public String getDapartment() {
        return dapartment;
    }

    public void setDapartment(String dapartment) {
        this.dapartment = dapartment;
    }
}

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>
    <!-- 配置环境 -->
    <environments default="mysql">
        <!-- 配置mysql的环境  -->
        <environment id="mysql">
            <!-- 配置事务的类型  -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源(连接池) -->
            <dataSource type="POOLED">
                <!-- 配置连接数据库的四个基本信息  -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/springsemester"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 指定映射配置文件的位置  -->
    <mappers>
        <mapper resource="com/example/mybatis_xml/dao/InterfaceUserDao.xml"/>
    </mappers>
</configuration>

InterfaceUserDao.java

  /**
   * UserMapper 接口,映射对数据库的操作
   */
  public interface InterfaceUserDao {
      /**
       * 以查询所有为例,其他操作大同小异
       */
      List<User> findAll();
  }

InterfaceUserDao.xml

<?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">

<!-- namespace是dao的全限定类名,定位的是InterfaceUserDao.java这个接口-->
<mapper namespace="com.example.mybatis_xml.dao.InterfaceUserDao">
    <!-- 配置查询所有,通过namespace找到InterfaceUserDao.java,再通过id找到findAll()方法 ,resultType标签是该方法返回的结果类型,显然在这里返回的是User-->
    <select id="findAll" resultType="com.example.mybatis_xml.entity.User">
        select * from mybatis_xml;
    </select>
</mapper>

MybatisProtoApplication

public class MybatisProtoApplication {

    public static void main(String[] args) throws Exception {
        // 1.读取配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(is);
        // 3.使用工厂生产SqlSession对象
        SqlSession session = factory.openSession();
        // 4.使用SqlSession对象创建dao接口代理对象
        InterfaceUserDao userDao = session.getMapper(InterfaceUserDao.class);
        // 5.使用代理对象执行方法
        List<User> listAll = userDao.findAll();
        for (User user : listAll) {
            System.out.println(user);
        }
        // 6.释放资源
        session.close();
        is.close();
    }
}

(2)、mapper代理对象 + 注解

使用动态代理机制,dao层接口化,底层自动创建代理对象代替dao对象创建SqlSession,并且自动从注解中提取sql。

MyBatis的常用注解

  • @Insert:实现新增

  • @Update:实现更新

  • @Delete:实现删除

  • @Select:实现查询

  • @Result:实现结果集封装

  • @Results:可以与@Result 一起用,封装多个结果集

  • @One:实现一对一结果集封装

  • @Many:实现一对多结果集封装

编写实体类

    @Getter
    @Setter
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    public class User implements Serializable {
        private int id;
        private String name;
        private int age;
        private String dapartment;
    }

UserMapper.java

/**
 * @author DF10F-0001A
 * @description: 基于注解开发的持久层接口
 */
public interface UserMapper {
    /**
     * 查询所有用户
     *
     * @return
     */
    @Select("select * from mybatis_annotation")
    List<User> findAll();
}

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>
    <!-- 配置别名的注册 -->
    <typeAliases>
        <package name="com.example.mybatis_annotation.entity"/>
    </typeAliases>
    <!-- 配置 mybatis 的环境 -->
    <environments default="mysql">
        <!-- 配置 mysql 的环境 -->
        <environment id="mysql">
            <!-- 配置事务的类型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置连接数据库的信息:用的是数据源(连接池) -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/springsemester?serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 配置映射信息 -->
    <mappers>
        <!-- 配置 dao 接口的位置,它有两种方式
            第一种:使用 mapper 标签配置 class 属性
            第二种:使用 package 标签,直接指定 dao 接口所在的包
            -->
        <package name="com.example.mybatis_annotation.mapper"/>
    </mappers>
</configuration>

测试类

@SpringBootTest
public class MybatisAnnotationApplicationTests{
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private UserMapper userMapper;
    @Before
    public void init() throws Exception {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        //3.创建 session
        session = factory.openSession();
        //4.创建代理对象
        userMapper = session.getMapper(UserMapper.class);
    }
    /**
     * 测试查询所有
     */
    @Test
    public void testFindAll() {
        List<User> users = userMapper.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

3、使用Map

当实体类,或者数据库中的表,字段或者参数过多,我们应该考虑使用Map!

Map传递参数,直接在sql中取出key即可! 【parameter=“map”】

对象传递参数,直接在sql中取出对象的属性即可! 【parameter=“Object”】

只有一个基本类型参数的情况下,可以直接在sql中取到

多个参数用Map , 或者注解!

UserMapper接口

public void addUser(Map<String,Object> map);

UserMapper.xml

<!--对象中的属性可以直接取出来 传递map的key-->
<insert id="addUser2" parameterType="map">
    insert into user (id,name,password) values (#{userid},#{username},#{userpassword})
</insert>

测试

    @Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("userid",4);
        map.put("username","王虎");
        map.put("userpassword",789);
        mapper.addUser2(map);
        //提交事务
        sqlSession.commit();
        //关闭资源
        sqlSession.close();
    }

4、模糊查询

Java代码执行的时候,传递通配符%

List<User> userList = mapper.getUserLike("%李%");

在sql拼接中使用通配符

select * from user where name like "%"#{value}"%"

三、配置解析

1、核心配置文件

MyBatis-config

<?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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://172.31.32.184:3306/constxiong?serverTimezone=UTC&amp;useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="constxiong@123"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="constxiong/mapper/UserMapper.xml"/>
    </mappers>
</configuration>
  • environments-default属性表示在默认的情况下我们将启用的数据源

  • environment-id代表当前环境的唯一标识

transactionManager type="JDBC

在 MyBatis 中有两种事务管理器类型(也就是 type=”[JDBC|MANAGED]”):

  • JDBC – 这个配置直接简单使用了 JDBC 的提交和回滚设置。 它依赖于从数据源得 到的连接来管理事务范围。

  • MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让 容器来管理事务的整个生命周期(比如 Spring 或 JEE 应用服务器的上下文) 默认 情况下它会关闭连接。 然而一些容器并不希望这样, 因此如果你需要从连接中停止 它,将 closeConnection 属性设置为 false。例如:

    <transactionManagertype="MANAGED">  <propertyname="closeConnection"value="false"/></transactionManager>

dataSource type="POOLED"

在里面可以放入配置数据库的基本连接信息(driver,url,username,password)同时在该标签上有一个属性type,它表示mybatis获取连接的方式。type属性有三个值,分别为unPooled,pooled和JNDI。

property属性

在使用 properties 标签配置时,我们可以采用两种方式指定属性配置

第一种

<properties> 
 <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/> 
 <property name="jdbc.url" value="jdbc:mysql://localhost:3306/xxx"/> 
<property name="jdbc.username" value="root"/> 
 <property name="jdbc.password" value="1234"/>
  </properties>

第二种

在 classpath 下定义 db.properties 文件 

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springdb
jdbc.user=root
jdbc.passwd=123456

  此时我们的 dataSource 标签就变成了引用上面的配置

 <?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">
    </properties>
    <!-- 和spring整合后 environments配置将废除 -->
    <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.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    <!-- 加载 映射文件 -->
    <mappers>
        <mapper resource="User.xml" />
        <mapper resource="UserMapper.xml" />
    </mappers>

</configuration>

Mapper

第一种依据 Mapper 类 具体路径 配置 Mapper

<configuration>  
    <mappers>       
        <!-- class 级别的指定 -->  
        <mapper class="com.bestcxx.stu.springmvc.mapper.UserModelMapper"/>  
        <mapper class="com.bestcxx.stu.springmvc.mapper.UserModelTwoMapper"/>  
    </mappers>  
</configuration>  

文件结构:

第二种依据 Mapper 类所在的package包路径 配置 Mapper

<configuration>  
    <mappers>  
        <package name="com.bestcxx.stu.springmvc.mapper"/>  
    </mappers>  
</configuration>  

文件结构:

第三种是把 Mapper 的xml配置文件单独放置到 resources 中,和Mapper 类分开了

<configuration>  
    <mappers>  
        <!-- 使用这个方案,可以单独指定Mapper的位置 -->  
        <mapper resource="mybatis/mappings/UserModelMapper.xml"/>  
        <mapper resource="mybatis/mappings/UserModelTwoMapper.xml"/>  
    </mappers>  
</configuration>  

文件结构:

Mapper类位置不变,Mapper.xml位置改变

2、属性优化

编写db.properties配置文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username=root
password=123456

在核心配置文件中引入

<!--引用外部配置文件-->
<properties resource="db.properties">
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</properties>

引用

<dataSource type="POOLED">
    <property name="driver" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
</dataSource>

注意:

  • 可以直接引入外部文件

  • 可以在其中增加一些属性配置

  • 如果两个文件有同一个字段,优先使用外部配置文件的

3、别名优化

  • 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置.

  • 意在降低冗余的全限定类名书写

可以给实体类起别名

<typeAliases>
    <typeAlias type="com.pojo.User" alias="User"/>
</typeAliases>

也可以指定一个包,每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author,;若有注解,则别名为其注解值。见下面的例子:

<typeAliases>
    <package name="com.pojo"/>
</typeAliases>

4、接口绑定

接口绑定就是把接口里的方法与对应执行的 SQL 进行绑定,以及 SQL 执行的结果与方法的返回值进行转换匹配。

(1)、注解绑定

//这种方式不用写mapper.xml
@Select("select * from `user` where id = #{id}")
	public teacher  selectTeacherByID(int id);

(2)、SQL绑定

  <select id="selectUserByID" parameterType="int" resultType="test.student">
        select id,name,age,stuCountry stu_country from `user` where id = #{id}
  </select>

四、映射器

映射器作用:

  • 定义参数类型 

  • 描述缓存 

  • 描述 SQL 语句 

  • 定义查询结果和POJO的映射关系 

1、映射器分类

(1)、xml映射器

Person p = session.selectOne("com.mybatis.mydemo.mapper.PersonMapper.selectPersonById", 1);

(2)、xml映射器+接口映射器的混合形式

PersonMapper pm = session.getMapper(PersonMapper.class);
// 直接调用接口的方法,查询id为1的Peson数据
Person p2 = pm.selectPersonById(1);

(3)、注解+接口映射器的混合形式

此类形式,将原先xml里面的sql配置信息,变成Java注解的形式写到接口映射器,用法与上面的例子雷同。

2、引入映射器

(1)、通过文件类路径引入XML映射器

<!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
<mappers>
    <mapper resource="com/dao/UserMapper.xml"/>
</mappers>

(2)、通过包名引入映射器接口

<mappers>
    <package name="com.dao"/>
</mappers>

(3)、用类注册引入映射器接口

<!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
<mappers>
    <mapper class="com.dao.UserMapper"/>
</mappers>
  • 接口和他的Mapper配置文件必须同名

  • 接口和他的Mapper配置文件必须在同一个包下

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

DF10F-0001A

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

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

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

打赏作者

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

抵扣说明:

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

余额充值