Hibernate 5.2.12 API详细指南

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Hibernate是一个流行的Java对象关系映射(ORM)框架,它简化了数据库编程。本压缩包包含Hibernate 5.2.12版本的API文档,提供配置、实体管理、持久化操作、懒加载、级联操作、事务管理、缓存、查询API、事件监听器和元数据等关键知识点的学习和查阅。对于开发者而言,深入理解这些内容将提升在项目中的数据库操作效率。 Hibernate

1. Hibernate API的配置与初始化方法

1.1 配置Hibernate环境

在开始使用Hibernate之前,配置其运行环境是必需的第一步。配置文件(通常是hibernate.cfg.xml)包含数据库连接信息、Hibernate映射文件的位置以及其它一些关键配置。在这一节,我们将详细介绍如何设置和配置Hibernate环境。

<!-- hibernate.cfg.xml 示例配置 -->
<hibernate-configuration>
    <session-factory>
        <!-- 数据库连接设置 -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/yourdb</property>
        <property name="connection.username">dbuser</property>
        <property name="connection.password">dbpass</property>
        <!-- 数据库方言 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- 可选:显示SQL语句 -->
        <property name="show_sql">true</property>
        <!-- 可选:映射文件位置 -->
        <mapping class="com.example.yourmodelclass" />
    </session-factory>
</hibernate-configuration>

1.2 初始化Session工厂

配置完成后,接下来需要初始化Session工厂,它是创建Session的工厂类。这通常是在应用程序启动时完成的。

// 初始化Session工厂
Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);

1.3 创建和关闭Session

Session是应用程序与持久化存储层交互的接口。使用Session工厂创建Session实例,并在操作完成后关闭Session。

// 创建Session
Session session = sessionFactory.openSession();
try {
    // 使用session进行CRUD操作
    ...
} finally {
    // 关闭Session
    session.close();
}

在这一章节中,我们学习了Hibernate的配置和初始化方法,为后续的高级操作打下了坚实的基础。

2. 深入理解Hibernate的Session操作和事务处理

2.1 Session的生命周期和状态管理

2.1.1 创建与打开Session

在Hibernate中,Session是应用程序与数据库交互的桥梁。它代表了一个会话期,其中包含了一组持久化对象与数据库之间交互的边界。创建Session对象通常通过 SessionFactory openSession 方法完成。

Session session = sessionFactory.openSession();

这里, sessionFactory 是在Hibernate配置完成后,根据配置信息创建的工厂对象。 openSession 方法负责创建一个新的 Session 实例,它连接到数据库并且准备进行操作。当通过 sessionFactory 来获取 Session 对象时,Hibernate会根据配置的连接池自动管理数据库连接,这样可以保证数据库连接的有效利用和重用。

创建Session后,就可以利用它来加载和保存实体数据了。但是需要注意的是,Session并不是永久打开的,开发者必须在事务结束时手动关闭它。

2.1.2 Session的持久化状态管理

Hibernate的Session状态管理主要与实体的生命周期紧密相关。实体在Hibernate中有几种状态,最常见的是瞬态、持久化状态和脱管状态。

  • 瞬态(Transient) : 实体对象刚被创建,与Session无关,还没有关联数据库。
  • 持久化状态(Persistent) : 实体对象已经被加载到Session中,或者通过Session保存或更新,与数据库相关联。
  • 脱管状态(Detached) : 实体对象曾经是持久化的,但是当前Session已经关闭,因此不再与Session关联。

管理这些状态的一个重要方面是理解它们之间的转换:

  • 从瞬态转换到持久化状态 :通常通过调用 session.save() 方法完成。
  • 从持久化状态转换到脱管状态 :通过 session.close() 或者调用 session.clear() session evict() 方法,实体将从Session中分离。
  • 从脱管状态转换回持久化状态 :重新获取一个Session,并使用这个新的Session对实体进行操作。
2.1.3 Session关闭和缓存清理

当实体操作完成后,应该关闭Session以释放相关资源。关闭Session会导致持久化上下文中所有更改被提交到数据库,并且关闭与数据库的连接。关闭Session的操作通常通过调用 session.close() 方法完成。

session.close();

关闭Session后,所有与该Session相关联的持久化实体将变为脱管状态。如果需要对这些实体进行进一步操作,则需要重新打开一个新的Session。

另外,Hibernate还提供了缓存机制,缓存包括了Session级别的快照缓存和一级缓存。在Session关闭时,Hibernate会清理一级缓存中的所有数据,确保不会保留不再需要的数据。如果需要手动清理缓存,可以在Session上调用 session.clear() 方法。

session.clear();

2.2 Hibernate事务处理机制

2.2.1 事务的概念和隔离级别

在数据库操作中,事务是一组操作的集合,这些操作要么全部成功,要么全部失败。Hibernate的事务处理与底层数据库事务紧密相关,Hibernate事务提供了原子性、一致性、隔离性和持久性(ACID)的保证。

Hibernate支持多种隔离级别,这些隔离级别定义了事务与其他事务的隔离程度。隔离级别越高,事务的并发性能越差,但可以避免更多的并发问题。Hibernate支持的隔离级别包括:

  • READ_UNCOMMITTED
  • READ_COMMITTED
  • REPEATABLE_READ
  • SERIALIZABLE
2.2.2 管理事务的API使用

Hibernate提供了编程式和声明式两种事务管理方式。编程式事务管理涉及代码中直接调用API来控制事务的边界和状态,而声明式事务管理则通常使用注解或者XML配置文件来实现。

使用Hibernate的 Session 对象管理事务是编程式事务管理的一个实例:

Session session = sessionFactory.openSession();
Transaction tx = null;
try {
    tx = session.beginTransaction();
    // 执行业务逻辑
    tx.commit();
} catch (Exception e) {
    if (tx != null) {
        tx.rollback();
    }
    throw e;
} finally {
    session.close();
}

在这段代码中,我们首先获取了一个 Session 对象,并开始了一个新的事务。在业务逻辑执行完毕后,我们提交事务。如果在执行过程中遇到异常,我们回滚事务以保持数据的一致性。

2.2.3 事务的边界和异常处理

事务的边界定义了事务的开始和结束。在Hibernate中,一个事务通常开始于调用 Session 对象的 beginTransaction() 方法,并在调用 commit() 方法时结束。如果在事务执行期间发生异常,应该捕获这些异常,并执行 rollback() 方法来撤销事务中的所有操作。

正确处理事务边界和异常,确保数据的一致性和完整性。对于运行时异常,应该始终回滚事务,而对于已检查异常,则需要根据业务逻辑决定是否回滚。

try {
    // 业务逻辑代码
} catch (RuntimeException e) {
    tx.rollback();
    throw e; // 重新抛出异常,通知上层调用者事务处理出错
} catch (Exception e) {
    // 对于已检查异常,决定是否回滚事务
    // 可以根据业务逻辑来判断
    tx.rollback();
    throw e;
} finally {
    if (tx != null) {
        tx.commit();
    }
    session.close();
}

在上面的代码中,我们不仅处理了运行时异常,还处理了已检查异常。异常处理应始终放在 try-catch-finally 块中,以确保即使发生异常,资源也能被正确释放。

在下一章节中,我们将深入探讨实体映射与持久化操作的实践,并具体演示如何通过注解和XML配置实现实体类的映射。

3. 实体映射与持久化操作的实践

3.1 实体类的映射技术

3.1.1 基于注解的映射

基于注解的映射方式是目前主流的方式之一,通过在实体类的属性上使用特定的注解来定义属性和数据库表之间的映射关系。这种方式使得代码更加清晰,并且易于理解和维护。Hibernate 从 3.5 版本开始支持 JPA 注解。

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "users")
public class User {
    @Id
    private Long id;
    private String name;
    private String email;
    // ... 其他属性和getter/setter方法
}

在上面的代码中,我们定义了一个简单的 User 实体类。使用 @Entity 注解来表示该类为一个实体类, @Table 注解用来指定映射到数据库中的表名。 @Id 注解用于标识实体类的主键属性。

使用基于注解的映射方法,通常不需要配置 XML 映射文件,但需要在 persistence.xml 中指定需要扫描实体类的包。

3.1.2 基于XML的映射

基于 XML 的映射方式则需要创建一个 XML 文件来明确指定实体类属性和数据库表之间的映射关系。这种方式在一些项目中仍然被采用,尤其是那些有着严格配置管理的大型企业级应用。

User.hbm.xml 示例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example.model">
    <class name="User" table="users">
        <id name="id" column="user_id">
            <generator class="native"/>
        </id>
        <property name="name" column="name"/>
        <property name="email" column="email"/>
    </class>
</hibernate-mapping>

以上 XML 文件定义了一个与 User 实体对应的映射文件,它指定了实体类的包名、表名以及属性和列的映射关系。同样需要在 persistence.xml 中声明映射文件。

3.1.3 混合映射策略

混合使用注解和 XML 映射可以结合两种技术的优点。通常,开发者可能会在实体类中使用注解来定义简单的映射,而对于复杂的映射关系,则可能使用 XML 来进行精确控制。

@Entity
@Table(name = "orders")
public class Order {
    @Id
    private Long id;
    private Date orderDate;
    // ... 其他属性和getter/setter方法

    // 注解无法描述的复杂关联映射
    @ElementCollection
    @CollectionTable(name = "order_details", joinColumns = @JoinColumn(name = "order_id"))
    @Column(name = "order_detail")
    private List<String> orderDetails;
}

在实体类中,我们使用注解定义了基本的映射,但对于复杂的集合类型关系,我们使用了 XML 文件 Order.hbm.xml 来完成映射配置。

3.2 持久化操作的深入探究

3.2.1 保存、更新和删除操作

Hibernate 提供了简洁的方法来对数据库进行 CRUD 操作。实体类在被加载到 Session 中时处于临时状态。一旦我们对它进行了保存、更新或删除操作,它就会变成持久化状态。

保存操作

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
User user = new User();
user.setName("John Doe");
user.setEmail("john.doe@example.com");
session.save(user); // 将用户保存到数据库
transaction.commit();
session.close();

更新操作

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
User user = session.get(User.class, 1L); // 获取ID为1的用户
user.setName("Jane Doe");
session.update(user); // 更新用户信息
transaction.commit();
session.close();

删除操作

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
User user = session.get(User.class, 1L);
session.delete(user); // 删除用户
transaction.commit();
session.close();

在执行更新或删除操作时,我们必须确保 Session 中加载的实体是最新的,避免并发更新导致的问题。

3.2.2 瞬态、持久化和脱管状态的区别与转换

实体的状态转换是 Hibernate 操作的一个重要概念。瞬态(Transient)、持久化(Persistent)和脱管(Detached)状态之间的转换是持久化操作的基础。

  • 瞬态(Transient)状态 :实体类的实例已经创建,但尚未与 Session 关联。
  • 持久化(Persistent)状态 :实体类的实例已经与 Session 关联,并且在数据库中存在对应的记录。
  • 脱管(Detached)状态 :实体类的实例曾经与 Session 关联,但是当前 Session 已经关闭。
flowchart LR
    A[瞬态] -->|调用save()| B[持久化]
    B -->|提交事务| C[数据库中存在数据]
    C -->|Session关闭| D[脱管]
    D -->|再次关联Session| B

3.2.3 批量操作和性能优化

批量操作是提高数据处理性能的重要手段之一。Hibernate 提供了多种批量操作的方法,这些方法可以在单次数据库操作中处理多条记录。

批量保存

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
for (User user : users) {
    session.save(user);
}
transaction.commit();
session.close();

批量更新

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("update User u set u.email = :newEmail where u.id = :id");
query.setParameter("newEmail", "newemail@example.com");
query.setParameter("id", 1L);
query.executeUpdate();
transaction.commit();
session.close();

性能优化

为了优化批量操作的性能,我们可以采取以下措施:

  • 使用 hibernate.jdbc.batch_size 配置来控制批量操作的大小。
  • 调整批处理中的缓存大小和状态跟踪,减少内存使用。
  • 确保使用正确的事务隔离级别,以避免数据不一致的问题。
graph LR
    A[开始批量操作] --> B[配置批处理大小]
    B --> C[调整会话缓存]
    C --> D[事务隔离级别]
    D --> E[执行批量操作]
    E --> F[性能优化完成]

通过以上的章节,我们了解了实体映射的不同方法以及如何进行持久化操作。在下文中,我们将探讨实体类映射技术的更深层次内容,包括高级特性与Hibernate的进阶应用。

4. 高级特性与Hibernate的进阶应用

4.1 懒加载技术的原理与实践

4.1.1 懒加载的基本概念

在Java持久化领域,尤其是使用Hibernate框架时,开发者经常遇到“懒加载”(Lazy Loading)这个术语。懒加载是一种在对象实际需要时才加载对象数据的技术,它是为了解决大量数据加载对系统性能造成的负面影响而设计的。通过使用懒加载,开发者可以控制数据的加载时机,从而优化应用性能。

4.1.2 实现懒加载的策略

Hibernate通过代理(Proxy)机制实现懒加载。在映射配置中,可以设置关联对象或集合的懒加载属性。例如,使用注解时,可以在 @ManyToOne @OneToMany 等注解中设置 fetch 属性为 FetchType.LAZY

以下是一个简单的实现懒加载的示例代码:

@Entity
public class Employee {
    @Id
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    private Department department;
}

这段代码中, Department 关联对象被标记为懒加载。这意味着只有当程序实际访问到 department 属性时,Hibernate才会发起数据库查询以加载 Department 对象的数据。

4.1.3 懒加载的性能影响及优化

虽然懒加载在很多情况下可以提高性能,但也不总是如此。在某些场景下,如大量对象被懒加载时,可能会导致N+1查询问题,即在查询一个对象时,如果访问了它的一个或多个延迟加载的关联对象,就会产生额外的数据库查询。

为了优化懒加载带来的性能问题,开发者可以采取以下措施:

  • 精细控制懒加载:仅在确实需要时才使用懒加载,并确保知道潜在的性能影响。
  • 使用批量操作:例如,批量抓取可以减少数据库的往返次数,通过一次性加载多个对象来优化性能。
  • 查询优化:例如使用HQL或Criteria API进行精确的查询控制,限制不必要数据的加载。
// 使用HQL实现批量抓取
Session session = sessionFactory.openSession();
String hql = "SELECT e FROM Employee e LEFT JOIN FETCH e.department";
List<Employee> employees = session.createQuery(hql, Employee.class).list();

4.2 级联操作的应用与理解

4.2.1 级联操作的类型和配置

级联操作允许开发者定义在执行特定操作时,如何将这些操作自动应用到相关的实体上。Hibernate提供了多种级联类型,包括:

  • CascadeType.ALL :所有操作级联。
  • CascadeType.PERSIST :保存操作级联。
  • CascadeType.MERGE :合并操作级联。
  • CascadeType.REMOVE :删除操作级联。
  • CascadeType.REFRESH :刷新操作级联。
  • CascadeType.DETACH :分离操作级联。

通过在映射配置中设置这些属性,可以控制级联行为。例如,在注解中:

@Entity
public class Employee {
    @Id
    private Long id;

    @ManyToOne(cascade = CascadeType.ALL)
    private Department department;
}

4.2.2 级联操作对性能的影响

级联操作可以减少在业务逻辑中手动管理对象状态同步的需要,从而提高开发效率。然而,不当的级联配置也可能导致性能下降,因为它可能会导致过多的数据库操作。

例如,如果设置了 CascadeType.ALL ,那么对某个父对象的更新操作可能会级联到所有子对象,这在大量数据时可能会产生过多的数据库写操作。因此,合理配置级联操作是非常重要的。

4.2.3 级联操作在复杂关系中的应用

在复杂的对象关系中,级联操作的配置要更加小心。在一对多关系中,如果父对象设置了 CascadeType.REMOVE ,则删除父对象时,所有相关的子对象也会被删除。这在某些业务场景中是有用的,但在其他情况下可能会导致意外的数据丢失。

@Entity
public class Department {
    @Id
    private Long id;

    @OneToMany(mappedBy = "department", cascade = CascadeType.REMOVE)
    private List<Employee> employees;
}

在上面的例子中,如果 Department 对象被删除,那么 Employee 对象也会被级联删除。因此,在这种关系中,需要谨慎使用级联删除操作。

4.3 Hibernate事务管理与ACID原则

4.3.1 事务的基本原则

事务是数据库操作的基本单元,它由一系列的数据库操作组成。事务具有ACID属性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。这些属性确保了数据库操作的可靠性和一致性。Hibernate事务管理通过编程式或声明式方式实现,提供了对事务的控制。

4.3.2 Hibernate事务管理API

Hibernate提供了一组用于管理事务的API,主要包括 Session 对象中的 beginTransaction() commit() rollback() 方法。例如:

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();

try {
    // 执行数据持久化操作
    session.save(employee);
    // 提交事务
    transaction.commit();
} catch (Exception e) {
    // 出现异常时回滚事务
    transaction.rollback();
} finally {
    // 关闭Session
    session.close();
}

4.3.3 事务的应用场景分析

在实际应用中,正确配置和使用Hibernate事务是保证数据一致性的重要手段。开发者应当根据业务逻辑的需要,合理配置事务的隔离级别和传播行为。

例如,如果一个应用在更新操作时,需要确保数据的最新状态,可以使用 Session.FlushMode.ALWAYS 来强制Hibernate在每次查询前刷新缓存。对于一些长事务操作,开发者可能需要设置合适的隔离级别来避免脏读、幻读等问题。

transaction.setIsolation(Isolation.READ_COMMITTED);

以上代码展示了如何设置事务的隔离级别为 READ_COMMITTED 。这样,事务将只读取已经提交的数据,防止脏读的发生。

5. Hibernate的二级缓存使用与高级配置

随着业务的扩展,数据访问性能逐渐成为系统性能瓶颈。Hibernate作为强大的持久化框架,其二级缓存功能为提升系统性能提供了强有力的支撑。本章节将深入探讨二级缓存的概念、配置和高级配置方法,以及二级缓存在实际应用中的效果和优化技巧。

5.1 二级缓存的概念与配置

5.1.1 二级缓存的作用与好处

二级缓存(Second-Level Cache,SLC)位于应用服务器层面,它提供了跨多个Session生命周期的数据共享。通过配置二级缓存,能够有效减少数据库的访问频率,从而降低数据库负载,并提高应用性能。

二级缓存的好处包括: - 数据访问速度的显著提升。 - 减少数据库的并发访问,避免性能瓶颈。 - 缓存共享数据,实现跨多个Session的数据一致性。

5.1.2 二级缓存的配置细节

Hibernate允许开发者对不同的实体类配置二级缓存。配置通常在hibernate.cfg.xml文件或者映射文件中指定。一个基本的二级缓存配置示例如下:

<hibernate-configuration>
    <session-factory>
        <!-- 其他配置 -->

        <!-- 开启二级缓存 -->
        <property name="cache.use_second_level_cache">true</property>
        <!-- 配置缓存提供者 -->
        <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

        <!-- 针对某个实体类启用二级缓存 -->
        <class-cache usage="read-write" class="com.example.EntityClass"/>

        <!-- 其他配置 -->
    </session-factory>
</hibernate-configuration>

5.1.3 缓存策略和使用场景

Hibernate提供了多种缓存策略,包括read-only(只读)、read-write(读写)和nonstrict-read-write(非严格读写)。每种策略适用于不同的场景:

  • read-only :适用于几乎不被修改的数据,如地区信息、省份信息等。
  • read-write :适用于那些会经常被读写的数据,需要保证数据的一致性。
  • nonstrict-read-write :适用于可以接受稍微过期数据的场景,例如商品价格信息。

5.2 查询API的高级特性探索

5.2.1 HQL和Criteria的使用技巧

Hibernate查询语言(HQL)和Criteria API是进行复杂查询的两种主要方式。它们都支持二级缓存,合理利用可以大幅提升查询性能。

HQL和Criteria的使用技巧如下: - 利用HQL中的 CacheMode 控制查询结果是否从二级缓存中获取。 - 使用Criteria API时,可以设置查询属性 setCacheable(true) 来启用二级缓存。 - 确保查询结果的集合属性也被缓存,以减少后续加载时的数据库访问。

5.2.2 命名查询和动态查询

命名查询是将查询语句保存在映射文件中,可以通过名称来调用。动态查询则是根据运行时的条件动态构建。对于经常使用的查询,将其命名为命名查询可以提高复用性并利用二级缓存。

5.2.3 分页和批量操作的高级特性

Hibernate支持分页查询,这是减少内存占用和提高用户响应速度的有效手段。分页操作可以通过二级缓存减少数据库访问次数。

批量操作通常涉及大量数据的处理,合理的二级缓存策略可以大大减少数据库的压力。例如,在批量更新时,可以将批量操作中涉及的数据尽可能保留在二级缓存中,以降低对数据库的重复访问。

5.3 反射API与元数据操作

5.3.1 反射API在Hibernate中的应用

Hibernate在运行时通过反射API来动态地访问和操作Java对象。对于二级缓存,反射API用于处理对象和其属性的存储和检索。

5.3.2 元数据的提取和操作

元数据(Metadata)在Hibernate中指的是对象模型的描述信息。通过元数据API,Hibernate能够了解对象属性的类型和结构,进而进行有效的缓存管理。

5.3.3 元数据在持久化策略中的作用

元数据在确定二级缓存存储哪些实体数据以及如何存储方面起到了关键作用。例如,对于拥有复杂属性关系的实体,元数据帮助Hibernate决定缓存策略和缓存容量。

5.4 Hibernate的高级特性概览

5.4.1 原生SQL查询和存储过程

原生SQL查询和存储过程是Hibernate支持的两种高级特性。它们可以在需要时直接执行原生SQL语句,并可以将结果集缓存到二级缓存中,以提高执行效率。

5.4.2 事件监听器和拦截器

Hibernate的事件监听器和拦截器提供了强大的扩展点,允许开发者在特定的生命周期事件发生时注入自定义逻辑。这些扩展点可以结合二级缓存,在适当的时机刷新或清除缓存。

5.4.3 与Spring框架的整合

Hibernate与Spring框架的整合,可以借助Spring的声明式事务管理和依赖注入特性,简化事务管理并加强对象的生命周期控制。Spring还支持利用AOP在方法调用前后进行缓存操作,进一步提升系统性能。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Hibernate是一个流行的Java对象关系映射(ORM)框架,它简化了数据库编程。本压缩包包含Hibernate 5.2.12版本的API文档,提供配置、实体管理、持久化操作、懒加载、级联操作、事务管理、缓存、查询API、事件监听器和元数据等关键知识点的学习和查阅。对于开发者而言,深入理解这些内容将提升在项目中的数据库操作效率。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值