MyBatis框架总结

一、Mybatis概述:

mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,
而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
mybatis 通过 xml 或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中
sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并
返回。
采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了 jdbc api 底层访问细节,使我
们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。

1.1、JDBC回顾:

public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //加载数据库驱动
            Class.forName("com.mysql.jdbc.Driver");
            //通过驱动管理类获取数据库链接
            connection = DriverManager
                    .getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "ro
                            ot", " root");
                            //定义 sql 语句 ?表示占位符
                            String sql = "select * from user where username = ?";
             //获取预处理 statement
            preparedStatement = connection.prepareStatement(sql);
            //设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的参数值
            preparedStatement.setString(1, "王五");
            //向数据库发出 sql 执行查询,查询出结果集
            resultSet = preparedStatement.executeQuery();
            //遍历查询结果集
            while (resultSet.next()) {
                System.out.println(resultSet.getString("id") + "
                        "+resultSet.getString(" username"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    以上代码没有做jdbc抽取封装

1.2、JDBC问题分析:

1、加载数据驱动、数据库链接创建、释放资源频繁造成系统资源浪费从而影响系统性能。如果使用数据库链接池可解决此问题。
2、Sql 语句在代码中硬编码问题,造成不易维护。
3、使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不确定,可能多也可能少,修改 sql 还要修改代码,系统不易维护。
4、对结果集解析存在硬编码(查询列名),sql 变化导致解析代码变化,系统不易维护,如果能将数据库记
录封装成 pojo 对象解析比较方便。

1.3Mybatis快速入门:

  1. 创建一个maven工程。
    省略。。。。。
  2. 在 pom.xml 文件中添加 Mybatis3.4.5 的坐标,如下。
   <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
    </dependencies>

3.编写一个实体类User。

 CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8;
 private Integer id;
    private String username;
    private Date birthday;
    private Character sex;
    private String address;

    public Integer getId() {
        return id;
    }

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

    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 Character getSex() {
        return sex;
    }

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

    public String getAddress() {
        return address;
    }

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

    public User(Integer id, String username, Date birthday, Character sex, String address) {
        this.id = id;
        this.username = username;
        this.birthday = birthday;
        this.sex = sex;
        this.address = address;
    }

    public User() {
    }

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

4.编写持久层接口 IUserDao。

package com.ajth.cn.dao;

import com.ajth.cn.pojo.User;

import java.util.List;

/**
 * @author xfd
 * @version 1.0
 * @date 2021/3/28 0028 22:36
 */
public interface IUserDao {

    //查询所有用户
    List<User> findAll();
}

5.编写持久层接口(IUserDao)的映射文件 IUserDao.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.itheima.dao.IUserDao">
    
    <!-- 配置查询所有操作 --> 
    <select id="findAll" resultType="com.ajth.cn.pojo.User">
      select * from user
    </select>
</mapper>

6.编写 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>
    <!-- 配置 mybatis 的环境 -->
    <environments default="mysql">
        <!-- 配置 mysql 的环境 -->
        <environment id="mysql">
            <!-- 配置事务的类型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置连接数据库的信息:用的是数据源(连接池) -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 告知 mybatis 映射配置的位置 -->
    <mappers>
        <mapper resource="com/ajth/cn/dao/IUserDao.xml"/>
    </mappers>
</configuration>

7.编写测试类

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

8.结果展示

log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
User{id=41, username='老王', birthday=Tue Feb 27 17:47:08 CST 2018, sex=, address='北京'}
User{id=42, username='小二王', birthday=Fri Mar 02 15:09:37 CST 2018, sex=, address='北京金燕龙'}
User{id=43, username='小二王', birthday=Sun Mar 04 11:34:34 CST 2018, sex=, address='北京金燕龙'}
User{id=45, username='传智播客', birthday=Sun Mar 04 12:04:06 CST 2018, sex=, address='北京金燕龙'}
User{id=46, username='老王', birthday=Wed Mar 07 17:37:26 CST 2018, sex=, address='北京'}
User{id=48, username='小马宝莉', birthday=Thu Mar 08 11:44:00 CST 2018, sex=, address='北京修正'}
User{id=49, username='华为', birthday=null, sex=, address='北京市顺义区'}
User{id=52, username='小米', birthday=Mon Aug 10 09:27:23 CST 2020, sex=, address='北京市顺义区'}

Process finished with exit code 0

1.4、Mybatis快速入门总结:

通过1.3的快速入门,发现mybatis使用是一件非常容易的事情。因为只需要编写dao接口并按照mybatis要求编写两个配置文件,就可以实现功能了。比使用JDBC方便多了。
但是这里面包含了许多细节,例如为什么会有工厂对象(SqlSessionFactory),为什么有了工厂之后还有构建者对象(SqlSessionFactoryBuilder),为什么IUserDao.xml在创建时有位置和文件名的要求等。

1.5、基于注解的Mybatis:

  1. 在持久层接口中添加注解
    //mybatis注解方式
    @Select("select * from user")
    User getAll();
  1. 修改 SqlMapConfig.xml
<!-- 告知 mybatis 映射配置的位置 -->
    <mappers>
        <mapper class="com.ajth.cn.dao.IUserDao"/>
    </mappers>

3.注意事项:
在使用基于注解的 Mybatis 配置时,请移除 xml 的映射配置(IUserDao.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>
    <!-- 配置 mybatis 的环境 -->
    <environments default="mysql">
        <!-- 配置 mysql 的环境 -->
        <environment id="mysql">
            <!-- 配置事务的类型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置连接数据库的信息:用的是数据源(连接池) -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 告知 mybatis 映射配置的位置 -->
   <!-- <mappers>
        <mapper resource="com/ajth/cn/dao/IUserDao.xml"/>
    </mappers>-->
	<!--如果是用注解来配置的话,此处应该使用dao全限定类名-->
    <mappers>
        <mapper class="com.ajth.cn.dao.IUserDao"/>
    </mappers>
</configuration>

1.6、基于代理 Dao 实现 CRUD 操作

注意事项(
1.dao接口和dao接口的映射文件必须在相同包下。
2.接口映射文件中 namespace标签的值必须写对应的dao接口的全限定类型。
3.SQL 语句的配置标签,,,的 id 属性必须和持久层接口的
方法名相同。

1.创建一个maven项目
2.导入所需依赖

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ajth.cn</groupId>
    <artifactId>mybatis_day02</artifactId>
    <version>1.0-SNAPSHOT</version>


    <!-- 导入mybatis依赖-->
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

</project>

3.编写dao接口

package com.ajth.cn.dao;

import com.ajth.cn.pojo.User;
import org.apache.ibatis.annotations.Param;

/**
 * @author xfd
 * @version 1.0
 * @date 2021/3/29 0029 22:44
 */
public interface IUserDao {

    //保存用户
    boolean saveUser(User user);

    //删除一条用户记录
    boolean deleteUserById(Integer id);

    //根据id修改某条用户
    boolean updateById(User user);

    //根据id查询一条用户记录
    User findById(Integer id);
}


4.编写映射文件

<?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.ajth.cn.dao.IUserDao">

    <!--
     parameterType:
        入参类型,和接口中方法的入参类型一致。

     resultType:
        返回类型,和接口中方法的返回值类型一致。

     #{}:
        占位符相当于JDBC中的?,可以防止SQL注入。如果数据类型是基本数据类型
     可以随意写。

     #{}:内容写法
        由于保存方法的入参是一个User类型的对象,所以#{}中要写user对象中的属性名称。

    ognl 表达式:
        它是 apache 提供的一种表达式语言,全称是:
        Object Graphic Navigation Language 对象图导航语言
        它是按照一定的语法格式来获取数据的。
        语法格式就是使用 #{对象.对象}的方式

  -->
    <!--保存用户-->
    <insert id="saveUser" parameterType="com.ajth.cn.pojo.User" >
        INSERT INTO USER ( username, birthday, sex, address )
        VALUE
        (#{username},#{birthday},#{sex},#{address})
    </insert>

    <!--根据id删除一条记录-->
    <delete id="deleteUserById" parameterType="Integer">

      DELETE
        FROM
	  `user`
        WHERE
	    id = #{ssss}
    </delete>

    <!--根据id修改一条记录-->
    <update id="updateById" parameterType="com.ajth.cn.pojo.User">
      UPDATE USER
	SET username =#{username},
	birthday =#{birthday},
	sex =#{sex},
	address=#{address}
	WHERE id=#{id}
    </update>

    <!-- 根据id查询 -->
    <select id="findById" parameterType="Integer" resultType="com.ajth.cn.pojo.User">
        SELECT
        *
        FROM
        USER
        WHERE
        id = #{id}
    </select>



</mapper>

5.编写Mybatis核心配置文件

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

    <!-- 告知 mybatis 映射配置的位置 -->
   <mappers>
        <mapper resource="com/ajth/cn/dao/mapp/IUserDao.xml"/>
    </mappers>
</configuration>

6.编写测试类

package com.ajth.cn.test;


import com.ajth.cn.dao.IUserDao;
import com.ajth.cn.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.Date;

/**
 * @author xfd
 * @version 1.0
 * @date 2021/3/29 0029 22:49
 */
public class UserTest {

    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IUserDao userDao;


    //在测试方法执行之前执行
    @Before
    public void init() throws Exception {
//1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建构建者对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.创建 SqlSession 工厂对象
        factory = builder.build(in);
//4.创建 SqlSession 对象
        session = factory.openSession();
//5.创建 Dao 的代理对象
        userDao = session.getMapper(IUserDao.class);
    }


    @Test
    public void testFindOne() {
        User user = userDao.findById(41);
        System.out.println(user);
    }

    @Test
    public  void testSaveUser(){
        User user = new User();
        user.setUsername("王艳飞");
        user.setBirthday(new Date());
        user.setSex('男');
        user.setAddress("河北省邢台市");
        boolean flage = userDao.saveUser(user);
        if (flage){
            System.out.println("保存成功");
        }else{
            System.out.println("保存失败");
        }
    }

    @Test
    public  void testDeleteUser(){

        User byId = userDao.findById(53);

        boolean flag = userDao.deleteUserById(byId.getId());

        if(flag){
            System.out.println("删除成功");
        }else {
            System.out.println("删除失败");
        }
    }

    @Test
    public  void testUpdateById(){

        User user = new User();
        user.setId(41);
        user.setUsername("张宝宝");
        user.setBirthday(new Date());
        user.setSex('女');
        user.setAddress("湖北武汉");

        boolean flage = userDao.updateById(user);
        if(flage){
            System.out.println("修改成功");
        }else{
            System.out.println("修改失败");
        }


    }

    //在测试方法执行完成之后执行
    @After
    public void destroy() throws Exception {
        session.commit();
//7.释放资源
        session.close();
        in.close();
    }
}

1.7、Mybatis 与 JDBC 编程对比

1.数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:
在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。

2.Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。
解决:
将 Sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。
3.向 sql 语句传参数麻烦,因为 sql 语句的 where 条件不一定,可能多也可能少,占位符需要和参数对应。
解决:
Mybatis 自动将 java 对象映射至 sql 语句,通过 statement 中的 parameterType 定义输入参数的
类型。
4.对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo 对
象解析比较方便。
解决:
Mybatis 自动将 sql 执行结果映射至 java 对象,通过 statement 中的 resultType 定义输出结果的
类型。

1.8、Mybatis参数深入了解

parameterType 配置参数:

该属性的值可以是基本数据类型和String,也可以是实体类对象,还可以是实体类包装类对象。
基本数据类型和String可以直接写类名称,也可以写包名.类名的方式例如:
java.lang.String
实体类对象可以写权限定类名,也可以写别名假如你配置了别名)。

为什么基本数据类型和String就可以直接写类名,而实体类对象如果不配置别名就不可以使用呢?因为Mybatis在加载的时候已经把常用的基本数据类型和String注册了别名,所以可以使用。

一下是来自Mybatis官网
在这里插入图片描述
在这里插入图片描述
1.基本数据类型演示

  <!--根据id删除一条记录-->
    <delete id="deleteUserById" parameterType="Integer">

      DELETE
        FROM
	  `user`
        WHERE
	    id = #{ssss}
    </delete>

	  <!-- 根据id查询 -->
    <select id="findById" parameterType="Integer" resultType="com.ajth.cn.pojo.User">
        SELECT
        *
        FROM
        USER
        WHERE
        id = #{id}
    </select>

2.实体类对象类型演示

 <!--保存用户-->
    <insert id="saveUser" parameterType="com.ajth.cn.pojo.User" >
        INSERT INTO USER ( username, birthday, sex, address )
        VALUE
        (#{username},#{birthday},#{sex},#{address})
    </insert>

3.包装类对象演示

<!-- 根据QueryVO中条件查询用户信息 -->
    <select id="findUserNameByQueryVo"  resultType="com.ajth.cn.pojo.User" parameterType="com.ajth.cn.pojo.QueryVO">

        SELECT * FROM USER WHERE username LIKE '%${user.username}%'
    </select>

resultType 配置结果类型

1.基本数据类型演示

<!-- 查询总记录条数 -->
    <select id="countUser" resultType="int">

        SELECT COUNT(*) from USER
    </select>

2.实体类对象类型演示

 <!--根据id修改一条记录-->
    <update id="updateById" parameterType="com.ajth.cn.pojo.User">
      UPDATE USER
	SET username =#{username},
	birthday =#{birthday},
	sex =#{sex},
	address=#{address}
	WHERE id=#{id}
    </update>

1.9动态sql

  <!--

        if动态sql演示:
            注意test中写的是实体类对象中的属性属性,如果是包装类使用OGNL表达式写法。

    -->
    <select id="findUserByUserNameAndAddressIf" resultMap="userMap" parameterType="user">
        <include refid="userCommon"></include> WHERE 1=1
        <if test="userName != null and userName != '' ">
            AND username LIKE #{userName}
        </if>
        <if test="userAddress != null and userAddress != '' ">
            AND address LIKE #{userAddress}
        </if>
    </select>

    <!--动态sql之where演示-->
    <select id="findUserByUserNameAndAddressWhere" resultMap="userMap" parameterType="user">
        <include refid="userCommon"></include>
        <where>
          <if test="userName != null and userName != '' ">
            AND username LIKE #{userName}
          </if>
          <if test="userAddress != null and userAddress != '' ">
            AND address LIKE #{userAddress}
          </if>
        </where>
    </select>
   <!-- 动态sql之foreach演示-->
    <select id="findUserByUserNameAndAddressForeach" resultMap="userMap" parameterType="queryVo">
        <include refid="userCommon"></include>
        <where>
            <if test="ids != null and ids.size() > 0 ">
                <foreach collection="ids" open="id in ( " close=")" item="uid" separator=",">
                    #{uid}
                </foreach>
            </if>
        </where>
    </select>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值