mybatis

笔记

mybatis

第一章
  1. 三层架构
     界面层: 和用户打交道的, 接收用户的请求参数, 显示处理结果的。(jsp ,html ,servlet)
     业务逻辑层: 接收了界面层传递的数据,计算逻辑,调用数据库,获取数据
     数据访问层: 就是访问数据库, 执行对数据的查询,修改,删除等等的。


     三层对应的包
       界面层: controller包 (servlet)
       业务逻辑层: service 包(XXXService类)
       数据访问层: dao包(XXXDao类)


     三层中类的交互
       用户使用界面层--> 业务逻辑层--->数据访问层(持久层)-->数据库(mysql)

     
     三层对应的处理框架
       界面层---servlet---springmvc(框架)
       业务逻辑层---service类--spring(框架)
       数据访问层---dao类--mybatis(框架)

 
 2.框架
   框架是一个舞台, 一个模版

   模版:
     1. 规定了好一些条款,内容。
     2. 加入自己的东西

   框架是一个模块
    1.框架中定义好了一些功能。这些功能是可用的。
    2.可以加入项目中自己的功能, 这些功能可以利用框架中写好的功能。


   框架是一个软件,半成品的软件,定义好了一些基础功能, 需要加入你的功能就是完整的。
   基础功能是可重复使用的,可升级的。

   框架特点:
    1. 框架一般不是全能的, 不能做所有事情
    2. 框架是针对某一个领域有效。 特长在某一个方面,比如mybatis做数据库操作强,但是他不能做其它的。
    3. 框架是一个软件

 

 mybatis框架
   一个框架,早期叫做ibatis,  代码在github。
   mybatis是 MyBatis SQL Mapper Framework for Java (sql映射框架)
   1)sql mapper :sql映射
         可以把数据库表中的一行数据  映射为 一个java对象。
     一行数据可以看做是一个java对象。操作这个对象,就相当于操作表中的数据

   2) Data Access Objects(DAOs) : 数据访问 , 对数据库执行增删改查。


 mybatis提供了哪些功能:
  1. 提供了创建Connection ,Statement, ResultSet的能力 ,不用开发人员创建这些对象了
  2. 提供了执行sql语句的能力, 不用你执行sql
  3. 提供了循环sql, 把sql的结果转为java对象, List集合的能力
      while (rs.next()) {
        Student stu = new Student();
        stu.setId(rs.getInt("id"));
        stu.setName(rs.getString("name"));
        stu.setAge(rs.getInt("age"));
        //从数据库取出数据转为 Student 对象,封装到 List 集合
        stuList.add(stu);
      }
  4.提供了关闭资源的能力,不用你关闭Connection, Statement, ResultSet


 开发人员做的是: 提供sql语句
 最后是: 开发人员提供sql语句--mybatis处理sql---开发人员得到List集合或java对象(表中的数据)

 总结:
  mybatis是一个sql映射框架,提供的数据库的操作能力。增强的JDBC,
  使用mybatis让开发人员集中精神写sql就可以了,不必关心Connection,Statement,ResultSet
  的创建,销毁,sql的执行。

 

 第二章:
  1 主要类的介绍
   1) Resources: mybatis中的一个类, 负责读取主配置文件
      InputStream in = Resources.getResourceAsStream("mybatis.xml");

    2)SqlSessionFactoryBuilder : 创建SqlSessionFactory对象,
         SqlSessionFactoryBuilder builder  = new SqlSessionFactoryBuilder();
        //创建SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(in);

  3)SqlSessionFactory : 重量级对象, 程序创建一个对象耗时比较长,使用资源比较多。
        在整个项目中,有一个就够用了。

     SqlSessionFactory:接口  , 接口实现类: DefaultSqlSessionFactory
      SqlSessionFactory作用: 获取SqlSession对象。SqlSession sqlSession = factory.openSession();

      openSession()方法说明:
       1. openSession() :无参数的, 获取是非自动提交事务的SqlSession对象
        2. openSession(boolean): openSession(true)  获取自动提交事务的SqlSession.
                                 openSession(false)  非自动提交事务的SqlSession对象

 
 4)SqlSession:
   SqlSession接口 :定义了操作数据的方法 例如 selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()
   SqlSession接口的实现类DefaultSqlSession。

    使用要求: SqlSession对象不是线程安全的,需要在方法内部使用, 在执行sql语句之前,使用openSession()获取SqlSession对象。
    在执行完sql语句后,需要关闭它,执行SqlSession.close(). 这样能保证他的使用是线程安全的。


第三章:
  1. 动态代理: 使用SqlSession.getMapper(dao接口.class) 获取这个dao接口的对象
  2. 传入参数: 从java代码中把数据传入到mapper文件的sql语句中。
     1)parameterType : 写在mapper文件中的 一个属性。 表示dao接口中方法的参数的数据类型。
         例如StudentDao接口
          public Student  selectStudentById(Integer id)

      2) 一个简单类型的参数:
     简单类型: mybatis把java的基本数据类型和String都叫简单类型。
     在mapper文件获取简单类型的一个参数的值,使用 #{任意字符}

      接口:public Student  selectStudentById(Integer id)
      mapper:select id,name, email,age from student where id=#{studentId}

    3) 多个参数,使用@Param命名参数
      接口 public List<Student> selectMulitParam(@Param("myname") String name, @Param("myage") Integer age)
      使用  @Param("参数名")  String name
     mapper文件:
         <select>
             select * from student where name=#{myname} or age=#{myage}
          </select>

    4) 多个参数,使用java对象
       语法 #{属性名}

   vo: value object , 放一些存储数据的类。比如说 提交请求参数, name ,age
         现在想把name ,age 传给一个service 类。

   vo: view object , 从servlet把数据返回给浏览器使用的类,表示显示结果的类。

   pojo: 普通的有set, get方法的java类。 普通的java对象

          Servlet --- StudentService( addStudent( MyParam  param)  )

   entity(domain域): 实体类, 和数据库中的表对应的类,
     

    5) # 和  $

      select id,name, email,age from student where id=#{studentId}
      # 的结果: select id,name, email,age from student where id=?


       select id,name, email,age from student where id=${studentId}
      $ 的结果:select id,name, email,age from student where id=1001

      String sql="select id,name, email,age from student where id=" + "1001";
      使用的Statement对象执行sql, 效率比PreparedStatement低。


      $:可以替换表名或者列名, 你能确定数据是安全的。可以使用$


      # 和 $区别
      1. #使用 ?在sql语句中做站位的, 使用PreparedStatement执行sql,效率高
      2. #能够避免sql注入,更安全。
      3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
      4. $有sql注入的风险,缺乏安全性。
      5. $:可以替换表名或者列名


 3. mybatis的输出结果
    mybatis执行了sql语句,得到java对象。

     1)resultType结果类型, 指sql语句执行完毕后, 数据转为的java对象, java类型是任意的。
       resultType结果类型的它值 1. 类型的全限定名称   2. 类型的别名, 例如 java.lang.Integer别名是int
   

        处理方式:
           1. mybatis执行sql语句, 然后mybatis调用类的无参数构造方法,创建对象。
            2. mybatis把ResultSet指定列值付给同名的属性。


            <select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student">
          select id,name, email,age from student
        </select>

          对等的jdbc
          ResultSet rs = executeQuery(" select id,name, email,age from student" )
          while(rs.next()){
               Student  student = new Student();
                    student.setId(rs.getInt("id"));
                    student.setName(rs.getString("name"))
          }

   2) 定义自定义类型的别名
       1)在mybatis主配置文件中定义,使<typeAlias>定义别名
        2)可以在resultType中使用自定义别名


   3)resultMap:结果映射, 指定列名和java对象的属性对应关系。
        1)你自定义列值赋值给哪个属性
         2)当你的列名和属性名不一样时,一定使用resultMap


         resultMap和resultType不要一起用,二选一


第四章动态sql
 动态sql: sql的内容是变化的,可以根据条件获取到不同的sql语句。
           主要是where部分发生变化。

 动态sql的实现,使用的是mybatis提供的标签, <if> ,<where>,<foreach>

 1)<if>是判断条件的,
   语法<if test="判断java对象的属性值">
            部分sql语句
        </if>

 2)<where> 用来包含 多个<if>的, 当多个if有一个成立的, <where>会自动增加一个where关键字,
            并去掉 if中多余的 and ,or等。

 3)<foreach> 循环java中的数组,list集合的。 主要用在sql的in语句中。
    学生id是 1001,1002,1003的三个学生

     select * from student where id in (1001,1002,1003)

     public List<Student> selectFor(List<Integer> idlist)

     List<Integer> list = new ...
     list.add(1001);
     list.add(1002);
     list.add(1003);

     dao.selectFor(list)


     <foreach collection="" item="" open="" close="" separator="">
             #{xxx}
    </foreach>

    collection:表示接口中的方法参数的类型, 如果是数组使用array , 如果是list集合使用list
     item:自定义的,表示数组和集合成员的变量
     open:循环开始是的字符
     close:循环结束时的字符
    separator:集合成员之间的分隔符


  4)sql代码片段, 就是复用一些语法
    步骤
     1.先定义 <sql id="自定义名称唯一">  sql语句, 表名,字段等 </sql>
    2.再使用, <include refid="id的值" />


第五章:
  1. 数据库的属性配置文件: 把数据库连接信息放到一个单独的文件中。 和mybatis主配置文件分开。
     目的是便于修改,保存,处理多个数据库的信息。

      1)在resources目录中定义一个属性配置文件, xxxx.properties ,例如 jdbc.properties
        在属性配置文件中, 定义数据,格式是 key=value
          key: 一般使用 . 做多级目录的。
          例如 jdbc.mysql.driver    , jdbc.driver, mydriver
          jdbc.driver=com.mysql.jdbc.Driver
          jdbc.url=jdbc:mysql//.....
          jdbc.username=root
          jdbc.password=123456
         
      2)在mybatis的主配置文件,使用<property> 指定文件的位置
         在需要使用值的地方, ${key}

 2.mapper文件,使用package指定路径
     <mappers>
    
        <!--第二种方式: 使用包名
            name: xml文件(mapper文件)所在的包名, 这个包中所有xml文件一次都能加载给mybatis
            使用package的要求:
             1. mapper文件名称需要和接口名称一样, 区分大小写的一样
             2. mapper文件和dao接口需要在同一目录
        -->
        <package name="com.bjpowernode.dao"/>
    </mappers>

第六章:PageHelper

 PageHelper做数据分页的。

 

 

 

dao接口

package org.example.dao;

import org.apache.ibatis.annotations.Param;
import org.example.domain.Student;
import org.example.param.PrimaryStudent;
import org.example.param.QueryParam;

import java.util.List;
import java.util.Map;

public interface StudentDao {

    List<Student> selectStudents();
    Student selectStudentById(@Param("id") Integer id);
    int insertStudent(Student student);
    int updateStudent(Student student);
    //单参数传递
    int deleteStudent(int id);
    //使用@Param传参
    List<Student> selectStudentsMultiParam(@Param("myname") String name,@Param("myage") int age);
    //使用对象传递
    List<Student> selectStudentObject(QueryParam queryParam);
    //多参数使用map传参
    List<Student> selectStudentMap(Map<String,Object> map);
    //按位置传参
    List<Student> selectByNameAndAge(String name,int age);
    int countStudent();
    //map 作为返回值 如果查询结果为key - value 建议使用map,并且最多只能有一条记录
    Map<Object,Object> selectReturnMap(int id);
    //模糊查询 在java代码中使用模糊查询
    List<Student> selectLike(String name);
    //模糊查询,在mapper文件中使用模糊查询
    List<Student> selectLikeSecond(String name);
    //使用别名赋值
    List<PrimaryStudent> selectUseFieldAlias(QueryParam param);
    //动态sql if
    List<Student> selectStudentIf(Student student);
    //动态 SQL 之<where>
    List<Student> selectStudentWhere(Student student);
    //动态 SQL 之<foreach> 实现对集合的遍历
    List<Student> selectStudentForList(List<Integer> idList);
    //遍历 List<对象类型>
    List<Student> selectStudentForList2(List<Student> stuList);
    //SQl片段
    List<Student> selectStudentSqlFragment(List<Student> stuList);
    //使用pagehelper分页数据
    List<Student> selectAll();
}

Mapper

<?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 接口的全限定名称
--> <mapper namespace="org.example.dao.StudentDao">
    <!--o
    <select>: 查询数据, 标签中必须是 select 语句
    id: sql 语句的自定义名称,推荐使用 dao 接口中方法名称,
    使用名称表示要执行的 sql 语句
    resultType: 查询语句的返回结果数据类型,使用全限定类名
    -->
<!--    <resultMap id="studentMap" type="org.example.domain.Student">-->
<!--&lt;!&ndash;        主键字段使用id&ndash;&gt;-->
<!--        <id column="id" property="id"/>-->
<!--&lt;!&ndash;        非主键字段&ndash;&gt;-->
<!--        <result column="name" property="name"/>-->
<!--        <result column="email" property="email"/>-->
<!--        <result column="age" property="age"/>-->
<!--    </resultMap>-->


<!--    SQl代码片段,实现sql语句复用-->
    <sql id="studentSql">
        select id,name,email,age from student
    </sql>

    <select id="selectStudentSqlFragment"
               resultType="com.bjpowernode.domain.Student">
    <!-- 引用 sql 片段 -->
        <include refid="studentSql"/>
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")"
                 item="stuobject" separator=",">
                #{stuobject.id}
            </foreach>
        </if>
    </select>

    <select id="selectStudents" resultType="org.example.domain.Student">
        <!--要执行的 sql 语句-->
        select id,name,email,age from student
    </select>
<!--    基本数据类型无需写resultType   #{}占位符-->
    <insert id="insertStudent">
        insert into student(id,name,email,age) values(#{id},#{name},#{email},#{age});
    </insert>
    <update id="updateStudent">
        update student set age = #{age} where id = #{id}
    </update>
    <delete id="deleteStudent">
        delete from student where id = #{id}
    </delete>
<!--    这里使用$避免不了sql注入,使用的是statement,效率低-->
    <select id="selectStudentById" resultType="org.example.domain.Student">
        select id,name,email,age from student where id = ${id}
    </select>
    <select id="selectStudentsMultiParam" resultType="org.example.domain.Student">
        select id,name,email,age from student where name = #{myname} and age =#{myage}
    </select>
    <select id="selectStudentObject" resultType="org.example.domain.Student">
        select id,name,email,age from student where name = #{queryName} or age = #{queryAge}
    </select>

    <select id="selectStudentMap" resultType="org.example.domain.Student">
        select id,name,email,age from student where name=#{myname} or age = #{myage}
    </select>
<!--    使用resultMap-->
<!--    <select id="selectStudentMap" resultMap="studentMap">-->
<!--        select id,name,email,age from student where name=#{myname} or age = #{myage}-->
<!--    </select>-->
    <select id="selectByNameAndAge" resultType="org.example.domain.Student">
        select id,name,email,age from student where name =#{arg0} or age =#{arg1}
    </select>
    <select id="countStudent" resultType="int">
        select count(*) from student;
    </select>
    <select id="selectReturnMap" resultType="java.util.HashMap">
        select name,email from student where id = #{id}
    </select>
    <select id="selectLike" resultType="org.example.domain.Student">
        select id,name,email,age from student where name like #{likename}
    </select>
    <select id="selectLikeSecond" resultType="org.example.domain.Student">
        select id ,name,email,age from student where name like "%" #{likename} "%"
    </select>
    <select id="selectUseFieldAlias" resultType="org.example.param.PrimaryStudent">
        select id as stuID,name as stuName,email as stuEmail,age as stuAge from student where name
        = #{queryName} or age = #{queryAge}
    </select>
    <select id="selectStudentIf" resultType="org.example.domain.Student">
        select id,name,email,age from student
        where 1=1
        <if test="name != null and name != ''">
            and name = #{name}
        </if>
        <if test="age > 0">
            and age = #{age}
        </if>
    </select>
    <select id="selectStudentWhere" resultType="org.example.domain.Student">
        select id,name,email,age from student
        <where>
            <if test="name != null and age != ''">
                name = #{name}
            </if>
            <if test="age > 0">
                and age = #{age}
            </if>
        </where>
    </select>
    <select id="selectStudentForList" resultType="org.example.domain.Student">
        select id,name,email,age from student
        <if test="list != null and list.size > 0">
            where id in
            <foreach collection="list" open="(" close=")"
                     item="stuid" separator=",">
                #{stuid}
            </foreach>
        </if>

    </select>

    <select id="selectStudentForList2"
            resultType="com.bjpowernode.domain.Student">
        select id,name,email,age from student
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")"
                     item="stuobject" separator=",">
                #{stuobject.id}
            </foreach>
        </if>
    </select>
    <select id="selectAll" resultType="org.example.domain.Student">
        select * from student order by id;
    </select>
</mapper>

mybatis.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的位置-->
    <properties resource="jdbc.properties"/>
<!--    开启日志-->

    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
    <typeAliases>
        <!--
        定义单个类型的别名
        type:类型的全限定名称
        alias:自定义别名
        -->

        <!--        <typeAlias type="org.example.domain.Student" alias="mystudent"/>-->
        <!--
        批量定义别名,扫描整个包下的类,别名为类名(首字母大写或小写都可以)
        name:包名
        -->
        <package name="org.example.domain"/>

    </typeAliases>
    <!--配置 mybatis 环境-->
    <environments default="mysql">
        <!--id:数据源的名称-->
        <environment id="mysql">
            <!--配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚)-->
            <transactionManager type="JDBC"/>
            <!--数据源 dataSource:创建数据库 Connection 对象
            type: POOLED 使用数据库的连接池,提高性能
            -->
            <dataSource type="POOLED">
                <!--连接数据库的四个要素-->
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--告诉 mybatis 要执行的 sql 语句的位置--> 
<!--        <mapper resource="org/example/dao/StudentDao.xml"/>-->
        <package name="org.example.dao"/>
    </mappers>

</configuration>

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

  <groupId>org.example</groupId>
  <artifactId>mybatis_demo</artifactId>
  <version>1.0-SNAPSHOT</version>



  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>

    </dependency>
<!--    加入mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
<!--    加入mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.10</version>
    </dependency>
  </dependencies>

  <build>

    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>


    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
<!--        JDK版本-->
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.1</version>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

MybatisUtil

package org.example.common;

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 javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;

public class MybatisUtil {

    private static SqlSessionFactory sqlSessionFactory = null;
    static{

        String config = "mybatis.xml";
        InputStream in = null;
        try {
             in = Resources.getResourceAsStream(config);

             sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);

        } catch (IOException e) {
            sqlSessionFactory = null;
            e.printStackTrace();
        } finally {
            if(in != null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }

    public static SqlSession getSqlSession(){
        SqlSession sqlSession = null;
        if(sqlSessionFactory != null){
            sqlSession = sqlSessionFactory.openSession();
        }
        return sqlSession;
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值