Hibernate 学习笔记

目录

Hibernate 配置文件解析

Hibernate通过读取默认的配置文件加载数据库配置信息,该配置文件应放于classpath根目录下,默认的配置文件名称为Hibernate.cfg.xml。在Hibernate.cfg.xml文件中,不仅包含数据库的配置信息,还包含了用户对Hibernate所设置的属性信息,如打印SQL语句、自动建表等。其配置方法如下:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools.                   -->
<hibernate-configuration>

    <session-factory>
    <!-- 数据库驱动 -->
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <!-- 数据库连接的URL -->
    <property name="connection.url">jdbc.mysql://localhost:3306/test</property>
    <!-- 数据库连接用户 -->
    <property name ="connection.username">root</property>
    <!-- 数据库连接密码 -->
    <property name="connection.password">111</property>
    <!-- Hibernate 方言 -->
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <!-- 打印SQL语句 -->
    <property name="show_sql">true</property>
    <!-- 映射文件 -->
    <mapping resource ="con/lyq/User.hbm.xml"/>
    </session-factory>

</hibernate-configuration>

Hibernate.cfg.xml文件的根元素为,每个元素可以有多个和子元素,通常情况下只有一个,每一个对应一个数据库;元素用来配置Hibernate属性信息;元素用来配置持久化类映射文件的相对路径。元素的常用属性及功能如表1所示。

Hibernate-configuration 配置文件<property>属性

在项目实施过程中,当底层数据库发生变化时,不需要更改程序的源代码,只需要更改配置文件Hibernate.cfg.xml即可,提高了Hibernate使用的灵活性,同样也体现了Hibernate对数据库的跨平台性。

建议在调试程序时将Hibernate.show_sql属性设置为true,这样在运行程序时,会在控制台输出SQL语句,便于程序的调试;在发布应用时,应将该属性设置为false,以减少信息的输出量,提高软件的运行性能。

编写持久化类

对象-关系映射(ORM)是Hibernate的基础。在Hibernate中,持久化类是Hibernate操作的对象,它与数据库中的数据表相对应,描述数据表的结构信息。在持久化类中,其属性信息与数据表中的字段相匹配。下面来看一个简单的持久化类。

public class User {
      private Integer id;           //ID编号
      private String name;        //姓名
      private boolean sex;        //性别
      public Integer getId() {
            return id;
      }
      public void setId(Integer id) {
            this.id = id;
      }
      public String getName() {
            return name;
      }
      public void setName(String name) {
            this.name = name;
      }
      public boolean isSex() {
            return sex;
      }
      public void setSex(boolean sex) {
            this.sex = sex;
      }
}

类User为用户持久化类,此类中定义了用户的基本属性,并提供相应的getXXX()与setXXX()方法。从这个类可以看出,持久化类遵循JavaBean命名约定。由于持久化类只是一个普通的类,并没有特殊的功能,也就是说它不依赖于任何对象(没有实现任何接口,也没有继承任何类),又被称为POJO类。Hibernate持久化类的编写遵循一定的规范,创建时需要注意以下几点。
l 声明一个默认的无参的构造方法
Hibernate在创建持久化类时,通过默认且没有参数的构造方法进行实例化,所以必须要提供一个无参的构造方法。
l 类的声明是非final类型的
如果Hibernate的持久化类声明为final类型,那么将不能使用延迟加载等设置,因为Hibernate的延迟加载通过代理实现;它要求持久化类是非final的。
l 拥有一个标识属性
标识属性通常对应数据表中的主键。此属性是可选的。为了更好地使用Hibernate,推荐加入此属性,如User类中的id属性。
l 为属性声明访问器
Hibernate在加载持久化类时,需要对其进行创建并赋值,所以在持久化类中属性声明getXXX()方法与setXXX()方法,这些方法为public类型。

编写映射文件

Hibernate的映射文件与持久化类相互对应,映射文件指定持久化类与数据表之间的映射关系,如数据表的主键生成策略、字段的类型、一对一关联关系等。它与持久化类的关系密切,两者之间相互关联。在Hibernate中,映射文件的类型为.xml格式,其命名方式规范为*.hbm.xml。例如,创建持久化类User对象的映射文件,代码如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"             "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
      <class name="com.lyq.model.User" table="tb_user">
            <id name="id" column="id" type="int">
                  <generator class="native"></generator>
            </id>
            <property name="name" type="string" not-null="true" length="50">
                  <column name="name"></column>
            </property>
            <property name="sex" type="boolean">
                  <column name="sex"/>
            </property>
      </class>
</hibernate-mapping>

(1)元素
元素是Hibernate映射文件的根元素,其他元素嵌入在元素内,其常用属性主要有package属性,用于指定包名。

(2)元素

元素用于指定持久化类和数据表的映射。其name属性指定持久类的完整类名(包含包名);table属性用于指定数据表的名称,如果不指定此属性,Hibernate将使用类名作为表名。

在元素中包含一个元素及多个元素,其中元素对应数据表中的标识,指定持久化类的OID和表主键的映射;元素描述数据表中字段的属性。

元素
通过name属性指定持久化类中的属性,column属性指定数据表中的字段名称,type属性用于指定字段的类型。元素的子元素用于配置数据表主键的生成策略,它通过class属性进行设置。Hibernate常用内置主键生成策略如表1所示。

hibernate 常用内置主键生成策略及说明

元素元素用于配置数据表中字段的属性信息,通过此元素能够详细地对数据表的字段进行描述。元素的常用配置属性如表2所示。

property元素常用配置属性及说明

在实际开发过程中,可以省略column属性及type属性的配置,在尚未配置它们的情况下,Hibernate默认使用持久化类中属性名及属性类型去映射数据表中的字段。但要注意,当持久化类中的属性名与数据库中SQL关键字相同时(如sum、group等),应该使用column属性指定具体的字段名称以示区分。
从映射文件可看出,它在持久化类与数据库之间起着桥梁的作用,映射文件的建立描述了持久化类与数据表之间的映射关系,同样也告知了Hibernate数据表的结构等信息。

Hibernate 基本数据类型的映射

Hibernate 的基本映射数据类型是Java基本类型与标准SQL类型间相互转换的桥梁.在前面的讲解中大家已经知道了.元素的type属性指定的就是映射类型.通过HIbernate 的映射关系可以非常方便的将数据从一种形式转换成另一种形式,完成高质量的ORM任务,表1列出了常用的Hibernate映射类型,Java基本类型与标准SQL 类型的对应关系 .

各种数据类型之间的对应关系

##hibernate 自动建表技术

面向对象的编程思想在Hibernate框架中体现得淋漓尽致,它将数据库中的数据表看作是对象,对数据的操作同样以对象的方式进行处理。在Hibernate中,对于数据表存在着面向对象中的继承等关系,因此在开发Hibernate项目时确定实体对象及实体与实体之间的关系极其重要。

在确定实体对象及关系后,可以通过Hibernate提供的自动建表技术导出数据表。具体实现方式有两种,本节将对其进行详细介绍。

  1. 手动导出数据表
    手动导出数据表用到org.hibernate.tool.hbm2ddl.SchemaExport类,其create()方法用于数据表的导出。

手动导出数据表,代码如下。

   public class ExportTables{
     public static void main(String[] args){
      Configuration cfg=new Configuration().configure(); //加载配置信息
      SchemaExport export=new SchemaExport(cfg);
      export.create(true,true);
      }
   }
  1. Hibernate 配置文件自动建表
    使用Hibernate配置文件进行自动建表,只需在Hibernate配置文件中加入配置代码即可。此种方法简单而又适用。
    例如:
<property name="hibernate.hbm2ddl.auto">create</property>
"

在Hibernate 配置文件中,hibernate.hbm2ddl.auto 属性用于设置自动建表,其取值有3种情况:

l create:使用此值,每次创建SessionFactory时都会重新创建数据表;如果数据表已存在将进行删除操作。要慎用。

l update:如果数据表不存在,则创建数据表;如果数据表存在,则检查数据表是否与映射文件相匹配,当不匹配时,更新数据表信息。

l none:使用此值,无论任何时候都不会创建或更新数据表。
在Hibernate框架的使用中,自动建表技术经常被用到,因为Hibernate对数据库操作进行了封装,符合Java面向对象的思维模式,当确定实体对象后,数据表也将自动被确定,从而为开发和测试提供了极大的方便。

编写Hibernate的初始化类

Hibernate的运行离不开Session对象,对于数据的增 删 改 查都要用到Session, 而Session对象依赖于SessionFactory对象,它需要通过SessionFactory进行获取,那么它是如何创建 又如何管理的Session呢?下面将对其进行详细讲解

  1. SessionFactory 的创建过程

Hibernate 通过Configuration类价值HIbernate配置信息,这主要是通过调用Configuration对象的configure(0方法来实现的,在默认情况下,Hibernate加载classpath目录下的”hibernate.cfg.xml” 文件.例如:

 Configuration cfg=new Configuration().configure();

加载完毕后通过Configuration对象的buildSessionFactory()方法创建SessionFactory对象,例如:

SessionFactory factory=cfg.bulidSessionFactory();
  1. 编写Hibernate 初始化类

    Session对象是操作数据库的关键对象,与SessionFactory对象关系密切.SessionFacroty对象并非轻量级,其创建过程需占用大量资源,而Session对象虽然是轻量级对象,但要做到及时获取与及时关闭,因此需要编写一个类对二者进行管理。

Hibernate的初始化类,代码如下。

public class HibernateUtil {
      private static SessionFactory factory = null;        //SessionFactory对象
      static {
            try {                 
                  Configuration cfg = new Configuration().configure();           //加载Hibernate配置文件
                  factory = cfg.buildSessionFactory();                                   //实例化SessionFactory
            } catch (HibernateException e) {
                  e.printStackTrace();
            }
      }
      public static Session getSession() {                                                        //编写获取session对象方法
            Session session = (factory != null) ? factory.openSession() : null;       //如果SessionFacroty不为空,则开启Session
            return session;
      }
      public static SessionFactory getSessionFactory() {                                  //编写获取SessionFactory对象方法
            return factory;
      }
      public static void closeSession(Session session) {                             //关闭session方法
            if (session != null) {
                  if (session.isOpen()) {
                        session.close();                                                    //关闭Session
                  }
            }
      }
}

SessionFactoty对象是重量级的对象,其创建过程比较耗时及占用资源,可以将其理解为是一个生产Session对象的工厂,当需要Session对象时从此工厂中获取即可,所以在整个程序的应用过程中最好只创建一次。例如,当用到一根钢筋时,可以到一个已存在的钢铁厂中去购买,而不需要去创建一个钢铁厂,再来生产所用的钢筋,这样的做法显得非常离谱。对程序而言,Session对象的应用是非常频繁的,如果用到Session对象就去创建一个SessionFactoty对象,将会对程序的性能产生一定的负作用。因此,在Hibernate初始化类中应将SessionFactoty对象的创建置于静态块中,实现在程序的应用过程中对其只创建一次,从而节省资源的占用。
但要注意Session对象并不是线程安全的,在涉及到多线程问题时,应该借助于ThreadLocal对象进行管理。

添加数据

添加数据用到Session接口的save()方法,其入口参数为Object类型,代表持久化对象。语法如下:

public Serializable save(Object obj)throws HibernateException 

obj:持久化对象,返回值:所生成的标识。

向数据库中添加药品信息,代码如下。

public class Save {
      public static void main(String[] args) {
            Session session = null;                                 //声明Session对象
            try {
                  session = HibernateUtil.getSession();              //获取Session
                  session.beginTransaction();                                  //开启事务
                  Medicine medicine = new Medicine();             //实例化药品对象,并对其属性赋值
                  medicine.setName("感冒药XX");
                  medicine.setPrice(5.00);
                  medicine.setFactoryAdd("XX制药一厂");
                  medicine.setDescription("最新感冒药");
                  session.save(medicine);                          //保存药品对象
                  session.getTransaction().commit();                //提交事物务
            } catch (Exception e) {
                  e.printStackTrace();
                  session.getTransaction().rollback();                //出错将回滚事务
            }finally{
                  HibernateUtil.closeSession(session);        //关闭Session对象
            }
      }
}

在执行save()方法之前,首先创建药品对象medicine,并对其属性赋值。此时medicine处于Transient(瞬时)状态,并没有在Session的管理之中。当提交事务后,medicine处于Persistent(持久)状态,已经在Session的管理之中,且数据库中存在与之匹配的数据,如图14.6所示。当Session关闭后,medicine脱离Session的管理,处于Detached(脱管)状态。

删除数据

在Hibernate中删除数据与添加、查询数据有所不同,因为要删除的对象并不在Session的管理之中,通过Session并不能对其进行删除操作,所以需要将要删除的对象转换为持久状态,使其处于Session的管理之内,然后再通过delete()方法进行删除。语法如下:

      public void delete(Object object) throws HibernateException

object:要删除的对象。

通过delete()方法删除药品信息,代码如下。

public class Delete {

      public static void main(String[] args) {

            Session session = null;                                               //声明Session对象

            try {

                  session = HibernateUtil.getSession();                       //获取Session

                  session.beginTransaction();                                      //开启事务

                  Medicine medicine = (Medicine)session.load(Medicine.class, new Integer(1));            //加载对象

                  session.delete(medicine);                                                 //输出药品信息

                  session.getTransaction().commit();                              //提交事务

            } catch (Exception e) {

                  e.printStackTrace();

                  session.getTransaction().rollback();                              //出错将回滚事务

            }finally{

                  HibernateUtil.closeSession(session);                      //关闭Session对象

            }

      }

}

在进行删除操作之前,程序首先加载了药品对象medicine,使其处于Persistent(持久)状态,然后再进行删除操作。

修改数据

Hibernate对数据的修改主要有两种情况:当实例对象处于Persistent(持久)状态时,对于它所发生的任何更新操作,Hibernate在更新缓存时都将会对其进行自动更新;另一种情况是Session接口提供了update()方法,调用此方法可对数据进行手动更新。

.自动更新
自动更新数据的方法与删除数据相似,在操作之前都需要加载数据,因为要修改的数据并没有处于Session的管理之内。当通过load()方法、get()方法加载数据后,持久化对象便处于Session的管理之内,即处于持久状态,在进行数据修改时,Hibernate将自动对数据进行更新操作。

修改药品信息,代码如下。

public class Update {

      public static void main(String[] args) {

            Session session = null;                                 //声明Session对象

            try {

                  session = HibernateUtil.getSession();              //获取Session

                  session.beginTransaction();                                  //开启事务

                  Medicine medicine = (Medicine)session.load(Medicine.class, new Integer(1));    //加载药品对象

                  medicine.setName("感冒胶囊");                           //修改药品名称

                  medicine.setPrice(10.05);                              //修改药品价格

                  session.getTransaction().commit();             //提交事务

            } catch (Exception e) {

                  e.printStackTrace();

                  session.getTransaction().rollback();                //出错将回滚事务

            }finally{

                  HibernateUtil.closeSession(session);        //关闭Session对象

            }

      }

}

对于Persistent(持久)状态的对象,Hibernate在更新缓存时将对数据进行对比,当对象发生变化时,Hibernate将更新数据。运行程序,Hibernate将发出两条SQL语句,如图1所示。

2.手动更新

手动更新主要是通过调用Session接口的update()方法来实现。语法如下:

public void update(Object obj) throws HibernateException

object:要更新的对象

通过update()方法修改药品信息,代码如下。

public class Update {

      public static void main(String[] args) {

            Session session = null;                                 //声明Session对象

            try {

                  session = HibernateUtil.getSession();              //获取Session

                  session.beginTransaction();                                  //开启事务

                  Medicine medicine = new Medicine();             //手动创建的Detached状态的药品对象

                  medicine.setId(1);                                 //药品ID

                  medicine.setName("感冒胶囊001");        //药品名称

                  session.update(medicine);                                 //更新药品信息

                  session.getTransaction().commit();             //提交事务

            } catch (Exception e) {

                  e.printStackTrace();

                  session.getTransaction().rollback();                //出错将回滚事务

            }finally{

                  HibernateUtil.closeSession(session);          //关闭Session对象

            }

      }

}

实例运行前,数据表中的数据如图2所示。由于程序中手动创建了Detached状态的药品对象,当更新数据时,对于持久化对象中没有值的属性也将会同步到数据库。

使用此种方法,虽然Hibernate只发出一条SQL语句,但对没有设置值的属性,数据表中将会同步为空值,所以应该慎用。

查询数据

Session接口提供了两个加载数据的方法,分别为get()方法与load()方法,它们都用于加载数据,但二者之间存在一定的区别。get()方法返回实际对象,而load()方法返回对象的代理,只有在被调用的时候,Hibernate才会发出SQL语句去查询对象。

1.get()方法

语法:

public Object get(Class entityClass,Serializable id) throws HibernateException

说明:

entityClass:持久化对象的类,id:标识,返回值:持久化对象或null值。

例如,获取编号为1的药品信息,代码如下:

Medicine medicine = (Medicine)session.get(Medicine.class, new Integer(1));           

//查询药品ID为1的药品

2.load()方法

语法:

public Object load(Class entityClass, Serializable id) throws HibernateException

说明:

entityClass:持久化对象的类,id:标识,返回值:持久化对象或null值。

例如,获取编号为1的商品信息,代码如下:

Medicine medicine = (Medicine)session.load(Medicine.class, new Integer(1));         

一级缓存

一级缓存是Session级的缓存,其生命周期很短,与Session相互对应。一级缓存由Hibernate进行管理,属于事务范围的缓存。

当程序调用Session的load()方法、get()方法、save()方法、saveOrUpdate()方法、update()方法或查询接口方法时,Hibernate会对实体对象进行缓存;当通过load()方法或get()方法查询实体对象时,Hibernate会首先到缓存中查询,在找不到实体对象的情况下,Hibernate才会发出SQL语句到数据库中查询,从而提高了Hibernate的使用效率。下面通过实例来了解一下一级缓存。

public class Test {
      public static void main(String[] args) {
            Session session = null;                          //声明Session对象
            try {
                  session = HibernateUtil.getSession();       //获取Session
                  session.beginTransaction();                           //开启事务
                  System.out.println("第一次查询:");
                  Medicine medicine1 = (Medicine)session.get(Medicine.class, new Integer(1));            //查询药品
                  System.out.println("药品名称:" + medicine1.getName());                               //输出药品名称
                  System.out.println("第二次查询:");
                  Medicine medicine2 = (Medicine)session.get(Medicine.class, new Integer(1));            //查询药品
                  System.out.println("药品名称:" + medicine2.getName());                               //输出药品名称
                  session.getTransaction().commit();         //提交事务
            } catch (Exception e) {
                  e.printStackTrace();
                  session.getTransaction().rollback();
            }finally{
                  HibernateUtil.closeSession(session);
            }
      }

程序通过get()方法第一次查询药品对象时,Hibernate会发出一条SQL语句进行查询,此时Hibernate对其药品对象进行了一级缓存;当再次通过get()方法查询时,Hibernate就不会发出SQL语句了,因为药品已存在于一级缓存中。

一级缓存的生命周期与Session相对应,它并不会在Session之间共享,在不同的Session中不能得到在其他Session中缓存的实体对象。

二级缓存

二级缓存是SessionFactory级的缓存,其生命周期与SessionFactory一致。二级缓存可以在多个Session间共享,属于进程范围或群集范围的缓存。
二级缓存是一个可插拔的缓存插件,它的使用需要第三方缓存产品的支持。在Hibernate框架中,通过Hibernate配置文件配置二级缓存的使用策略。
下面通过EHCache演示二级缓存的使用,其中主要包括以下两步。
l 加入缓存配置文件ehcache.xml。
ehcache.xml用于设置二级缓存的缓存策略,此文件位于下载的Hibernate的ZIP包下的etc目录中,在使用过程中需要将此文件加入到项目的src目录中。
l 设置Hibernate配置文件。
在配置文件hibernate.cfg.xml中,设置开启二级缓存及指定缓存产品提供商,同时还需要指定二级缓存应用到的实体对象,示例代码如下:

<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 指定缓存产品提供商 -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<!-- 映射文件 -->
<mapping resource="com/lyq/model/Medicine.hbm.xml" />
<!-- 指定二级缓存应用到的实体对象 -->
<class-cache class="com.lyq.model.Medicine" usage="read-only" />

对于二级缓存,可以使用一些不经常更新的数据或参考的数据,此时其性能会得到明显的提升。例如一个新闻网站,当发布一条热点新闻时,会有成千上万的访问量,而此条新闻并没有发生任何的变化,如果每一个用户访问都要查询数据库,将会在性能方面造成一定的问题,此时便可以考虑应用二级缓存。如果经常变化的数据应用二级缓存,则将失去意义。

Lazy 策略

Lazy策略为延迟加载策略,Hibernate通过JDK代理机制对其进行实现,它意味着使用延迟加载的对象,在获取对象的时候返回的是对象的代理,并不是对象的真正引用,只有在对象真正被调用的时候,Hibernate才会对其进行查询,返回真正的对象。
Lazy策略好比现实生活中用钱去买东西,如图1所示。在没有购买任何具体的物品时,“钱”只是一个代理对象,在购买成功之后,“钱”变成了实际的“物品”,也就相当于对象的代理返回了真正的对象引用;在购买物品之前,由于天气、时间等因素,将推迟一天购买此物品,此时相当于使用了Lazy策略进行延迟加载;在购买物品之前或延迟加载过程中,可能会有不需要此物品的情况发生,这样就不必购买此物品,从而节省了时间,这相当于JVM对其进行了垃圾回收。因此,使用Hibernate的延迟加载策略,在某种情况下将会对性能起到一定的优化作用。

此外,Hibernate的延迟加载还可以减少程序与数据库的连接次数,因为使用了延迟加载,Hibernate将延缓执行SQL语句,减少数据库的访问次数,提高执行的效率。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值