Hibernate学习总结(三)

目录

一、概要
二、映射表及属性
   2.1 映射表及普通属性
   2.2 不保存数据库的属性
   2.3 由数据库生成的属性
   2.4 映射枚举类型
   2.5 映射大数据类型属性
三、映射主键
   3.1 手动设置主键
   3.2 主键自动生成
     3.2.1 IDENTITY主键生成策略、
     3.2.2 UUID主键生成策略
四、映射集合
   4.1 List集合映射
   4.2 数组映射
   4.3 Set集合映射
   4.4 Map集合映射
   4.5 SortSet集合映射
   4.6 SortMap集合映射
五、组件映射
   5.1 映射普通组件
   5.2 组件包含集合
   5.3 集合中类型为组件
   5.4 组件作为Map索引

一、概要

本章主要介绍使用注解配置Hibernate,映射表、属性映射、主键映射、集合映射,其中重点介绍集合映射。

二、映射表及属性

2.1 映射表及普通属性

//entity表明为实体类
@Entity
//映射为person表,建立person_id,first_name联合索引,索引名为person_key
@Table(name="person",
      indexes={@Index(columnList="person_id,first_name",name="person_key",unique=true)})
public class Person {

    @Id
    @Column(name="person_id")
    //主键自增长策略,数据库字段生成
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer p_id;

    //firstName映射为person表中的first_name字段
    @Column(name="first_name",nullable=false,unique=false)
    private String firstName;

    @Column(name="last_name")
    private String lastName;

    //getter、setter、equals、hashcode....

}

Hibernate核心配置文件:

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

<hibernate-configuration>
    <session-factory>
    <!-- 1.配置数据库信息(必须配置) -->
        <!-- 数据库驱动类 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

         <!-- 数据库url,hibernate_demo为我们创建的数据库名称 -->
        <property name="hibernate.connection.url">jdbc:mysql:///hibernate_demo</property>

        <!-- 登录数据库的名称及密码 -->
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">123456</property>


    <!-- 2.配置hibernate信息(可选配置) -->
        <!-- 输出sql语句 -->
        <property name="hibernate.show_sql">true</property>

        <!-- 格式化输出的sql语句 -->
        <property name="hibernate.format_sql">true</property>

        <!-- 根据hbm配置文件里的数据库表,对数据库进行ddl操作,创建、删除... 
            update : 如果数据库中不存在hbm中配置的表,则先创建该表;
                      如果数据库中存在hbm中配置的表,则直接更新
        -->
        <property name="hibernate.hbm2ddl.auto">update</property>

        <!-- 配置数据库方言
            例如:如果对数据库进行分页查询,根据该配置,让hibernate识别数据库自身的关键字
                  mysql分页使用limit
                  oracle分页使用rownum
         -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 支持thread local session -->
        <property name="hibernate.current_session_context_class">thread</property>

        <property name="hibernate.c3p0.max_size">20</property>

        <property name="hibernate.c3p0.min_size">1</property>

        <property name="hibernate.c3p0.timeout">5000</property>

        <property name="hibernate.c3p0.max_statements">100</property>

        <property name="hibernate.c3p0.idle_test_period">3000</property>

        <property name="hibernate.c3p0.acquire_increment">2</property>

        <property name="hibernate.c3p0.validate">true</property>

        <!-- 3.添加映射配置文件(必须配置),这个地方与使用xml配置不同,标签为class -->
        <mapping class="cn.wh.mappingAttribute.Person"/>

    </session-factory>
</hibernate-configuration>

对应的person表:
这里写图片描述

DDL 信息

Create Table
CREATE TABLE `person` (
  `person_id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(255) DEFAULT NULL,
  `last_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`person_id`),
  UNIQUE KEY `person_key` (`person_id`,`first_name`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

@Table主键中,indexs用于建立索引,默认会建立主键索引。

测试代码及结果:

Transaction tx = session.beginTransaction();    
Person p = new Person();
p.setFirstName("wang");
p.setLastName("liu");
p.setGender(Gender.female); 
session.persist(p);

结果:

person_idfirst_namegenderlast_name
1wang0liu

2.2 不保存数据库的属性

@Formula(value="Select concat(p.first_name,p.last_name) from person p where p.id = id")
@Column(name="details")
private String details;

details有person表中的first_name和last_name两个字段连接构成,但是并不会保存在person表中

2.3 由数据库生成的属性

类似于数据库生成主键一样,属性值也可以由数据库生成

@Generated(value=GenerationTime.ALWAYS)
@Colum(name="comment")
private String comment;

这个时候需要配置数据库触发器一起使用,generated的value为ALways是,当执行select或update语句时,会根据触发器内容生成comment

2.4 映射枚举类型

@Enumerated(value=EnumType.ORDINAL)
@Column(name="gender")
private Gender gender;

enumerated的value为ordinal表示数据库中存放枚举值的序号,如果为string则表示数据库存放枚举值得名称

2.5 映射大数据类型属性

使用数据库保存图片、大段文章时使用@Lob、@Basic注解,主要通过byte[]保存内容

@Lob
@Column(name="pic")
private byte[] pic;

测试代码:

Person p = new Person();
p.setName("wh");
p.setAddress("hangzhou");
File file = new File("1.png");
byte[] contents = new byte[(int)file.length()];
new FileInputStream(file).read(contents);
p.setPic(contents);             
session.persist(p);

保存结果:
这里写图片描述

使用@Lob不能延迟加载,而使用@Basic则可以延迟加载,其用法和@Lob一样,只是使用的使用需要指定fetch属性,可选择FetchType.EAGER、FetchType.LAZY,另一个属性option则表示该列是否可以为null值
如下:

@Basic(fetch=FetchType.LAZY,optional=true)
private byte[] pic;

三、映射主键

3.1 手动设置主键

有时候我们需要手动设置主键值,不需要数据库自动生成,这个时候只要不配置主键生成策略即可,相对简单
Entity类:

@Entity
@Table(name="person1")
public class Person {

    @Id
    @Column(name="person_id")
    private Integer pid;

    @Column(name="person_name")
    private String name;

    //setter、getter、equals、hashcode...

DDL 信息:

Create Table
CREATE TABLE `person1` (
  `person_id` int(11) NOT NULL,
  `person_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

测试代码:

Person p = new Person();
p.setPid(12);
p.setName("wh");        
session.persist(p);

结果:

person_idperson_name
12wh

3.2 主键自动生成

此时手动设置主键id不生效,主键id由数据库根据我们配置的主键生成策略自动生成.

如果选用JPA支持的四种生成策略,即:AUTO(默认策略)、IDENTITY(主键自增长)、SEQUENCE、TABLE,则使用@GeneratedValue注解,如果选用Hibernate额外支持的策略,则使用@GenericGenerator,接下来使用IDENTITY和UUID举例说明

3.2.1 IDENTITY主键生成策略

Entity类:

@Entity
@Table(name="person1")
public class Person {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer pid;

    @Column(name="person_name")
    private String name;

    @Column(name="person_address")
    private String address;

    //setter、getter、equals、hashcode...

DDL信息:

CREATE TABLE `person1` (
  `person_id` int(11) NOT NULL AUTO_INCREMENT,
  `person_address` varchar(255) DEFAULT NULL,
  `person_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`person_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

测试代码:

Person p = new Person();
p.setName("wh");
p.setAddress("hangzhou");       
session.persist(p);

结果:

person_idperson_nameperson_address
1whhangzhou

3.2.2 UUID主键生成策略

Entity类:

@Entity
@Table(name="person1")
public class Person {

    @Id
    @Column(name="person_id")
    //定义注解生成器,名称为myUUID,生成策略为uuid
    @GenericGenerator(name="myUUID",strategy="uuid")
    //选择myUUID注解生成器
    @GeneratedValue(generator="myUUID")
    //使用string接受uuid值
    private String pid;

    @Column(name="person_name")
    private String name;

    @Column(name="person_address")
    private String address;

DDL信息:

CREATE TABLE `person1` (
  `person_id` int(11) NOT NULL AUTO_INCREMENT,
  `person_address` varchar(255) DEFAULT NULL,
  `person_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`person_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

测试代码:

Person p = new Person();
p.setName("wh");
p.setAddress("hangzhou");       
session.persist(p);

结果:
这里写图片描述

主键则增长策略比较多,很多都还没用过,以上两种用的比较多,所以就先记录两种


四、映射集合

映射集合时要求属性必须为集合接口,主要有Set、List、Map、SortSet、SortMap,使用@ElementCollection注解,集合默认延迟加载,数组不能延迟加载,使用fetch属性控制。

集合映射与后面介绍的级联映射最大的区别就是:集合映射中,集合保存的类型没有实体类,而级联映射中主表均存在实体类。

使用集合时,只能使用集合接口,不能使用具体的集合实现类,且需要初始化,因为Hibernate内部也实现了各个集合接口,会进行自动转换。

4.1 List集合映射

list集合映射,生成的从表,会使用list集合的下标建立索引列,且使用索引列和外键列建立联合主键
@Entity
@Table(name="Person_list")
public class Person {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer p_id;

    @Column(name="person_name")
    private String name;

    @Column(name="person_age")
    private Integer age;

    //指定集合映射,且集合中保存的类型为string
    @ElementCollection(targetClass=String.class)
    //指定映射表名,外键名为person_id,参考Person_list(主表)的person_id列,且不可为空
    @CollectionTable(name="schools_list",joinColumns=@JoinColumn(name="person_id",
                     referencedColumnName="person_id",nullable=false))
    //指定school_list表中保存list中内容的列名
    @Column(name="shool_name")
    //指定school_list表中的索引列名称,会使用arraylist的小标作为索引
    @OrderColumn(name="list_order")
    private List<String> schools = new ArrayList<String>();

    //setter/getter/equal/hashcode...

创建结果:
Person_list表:

CREATE TABLE `person_list` (
  `person_id` int(11) NOT NULL AUTO_INCREMENT,
  `person_age` int(11) DEFAULT NULL,
  `person_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`person_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
person_idperson_ageperson_name
127wh

schools_list表:

CREATE TABLE `schools_list` (
  `person_id` int(11) NOT NULL,
  `shool_name` varchar(255) DEFAULT NULL,
  `list_order` int(11) NOT NULL,
  PRIMARY KEY (`person_id`,`list_order`),
  CONSTRAINT `FKngoyt022vgypu537ablalqu5i` FOREIGN KEY (`person_id`) REFERENCES
   `person_list` (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 

使用外键列和索引列建立联合主键

IndexesColumnsIndex Type
PRIMARYperson_id,list_orderUnique

保存数据:

person_idshool_namelist_order
1hangyifuzhong0
1beiyifuxiao1
1shanghaizhongxue2

4.2 数组映射

数组和arrayList的使用方式一样,唯一的差别是数组是固定长度的,而arrayList是变长的。

@Entity
@Table(name="person_array")
public class Person {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer p_id;

    @Column(name="person_name")
    private String name;

    @Column(name="person_age")
    private Integer age;

    //使用方法,参数与arrayList一样
    @ElementCollection(targetClass=String.class)
    @CollectionTable(name="school_array",joinColumns=@JoinColumn(name="person_id",
                     referencedColumnName="person_id",nullable=false))
    @Column(name="school_name")
    @OrderColumn(name="array_order")
    private String[] schools = new String[20];

    //setter/getter/equals/hashcode...

保存数据:
person_array表:

person_idperson_ageperson_name
133lisan

school_array表:

person_idschool_namearray_order
1shanghaizhongxue0
1huayuanxiaoxue1

4.3 Set集合映射

Set集合的映射表没有索引,因为Set集合本身是无序的,Set表可能有联合主键,也可能没有联合主键。
@Entity
@Table(name="person_set")
public class Person {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer p_id;

    @Column(name="person_name")
    private String name;

    @Column(name="person_age")
    private Integer age;

    @ElementCollection(targetClass=String.class)
    @CollectionTable(name="school_set",joinColumns=@JoinColumn(name="person_id",
                     referencedColumnName="person_id",nullable=false))
    @Column(name="school_name",nullable=false)
    private Set<String> schools = new HashSet<String>();

    //setter/getter/equals/hashcode...

创建结果:
person_set表:

CREATE TABLE `person_set` (
  `person_id` int(11) NOT NULL AUTO_INCREMENT,
  `person_age` int(11) DEFAULT NULL,
  `person_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`person_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

school_set表:

CREATE TABLE `school_set` (
  `person_id` int(11) NOT NULL,
  `school_name` varchar(255) NOT NULL,
  PRIMARY KEY (`person_id`,`school_name`),
  CONSTRAINT `FKdonkua9tjs2tm20wt9ier8o54` FOREIGN KEY (`person_id`) 
  REFERENCES `person_set` (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
IndexesColumnsIndex Type
PRIMARYperson_id, school_nameUnique

set集合的映射表使用外键列和保存的内容列作为联合主键,没有索引列,如果保存的内容可以为空,则该表没有主键

4.4 Map集合映射

@Entity
@Table(name="person_map")
public class Person {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer p_id;

    @Column(name="person_name")
    private String name;

    @Column(name="person_age")
    private Integer age;

    @ElementCollection(targetClass=String.class)
    @CollectionTable(name="school_map",joinColumns=@JoinColumn(name="person_id",
                     referencedColumnName="person_id",nullable=false))
    //指定map中key值得类型
    @MapKeyClass(value=String.class)
    //指定map中key的存储列名
    @MapKeyColumn(name="school_index",nullable=false)
    @Column(name="school_name")
    private Map<String, String> schools = new HashMap<String, String>();

    //setter/getter/equals/hashcode...

创建结果:

person_map表:

CREATE TABLE `person_map` (
  `person_id` int(11) NOT NULL AUTO_INCREMENT,
  `person_age` int(11) DEFAULT NULL,
  `person_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`person_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

保存数据:

person_idperson_ageperson_name
113lisi

school_map表:

CREATE TABLE `school_map` (
  `person_id` int(11) NOT NULL,
  `school_name` varchar(255) DEFAULT NULL,
  `school_index` varchar(255) NOT NULL,
  PRIMARY KEY (`person_id`,`school_index`),
  CONSTRAINT `FK4mwmjgf4jp3o20es29dp8qi4r` FOREIGN KEY (`person_id`)
   REFERENCES `person_map` (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
IndexesColumnsIndex Type
PRIMARYperson_id, school_indexUnique

使用外键列和索引列建立联合主键

保存数据:

person_idschool_nameschool_index
1beijingsizhong000
1shanghaizhongxue001

4.5 SortSet集合映射

前面介绍了Set集合的映射,使用Set集合是无序的,使用SortSet集合时有序的,实现类时treeSet,使用@SortNatural和@SortComparator注解实现,其中前者是采用默认排序,后者需要提供value属性,该值是一个Comparator的实现类,使用定制排序。
@Entity
@Table(name="person_sortSet")
public class Person {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer pId;

    @Column(name="person_name")
    private String pName;

    @ElementCollection(targetClass=String.class)
    @CollectionTable(name="trains",joinColumns=@JoinColumn(name="person_id",
                     referencedColumnName="person_id",nullable=false))
    @Column(name="person_train",nullable=false)
    @SortNatural
    private SortedSet<String> trains = new TreeSet<String>();

    //setter/getter/equals/hashcode...

测试代码:

        Session session = HibernateUtils.getThreadLocalSession();
        Transaction tx = session.beginTransaction();

        Person p = new Person();
        p.setpName("hanmeimei");

        p.getTrains().add(new String("789"));
        p.getTrains().add(new String("123"));
        session.persist(p);

        tx.commit();

结果:
trains表:

person_idperson_train
1123
1789

4.6 SortMap集合映射

按照map的key值排序,类似于SortSet

五、组件映射

5.1 映射普通组件

即:entity中包含非普通类型变量,被引用的类中使用@Parent注解

方法一:

Person.java:

@Entity
@Table(name="person_embed")
public class Person {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer pId;

    @Column(name="person_address")
    private String pAddress;

    //组件
    private Name pName;

    //setter/getter/hashcode/equal...

组件Name.java:

@Embeddable
public class Name {
    @Column(name="first_name")
    private String firstName;

    @Column(name="last_name")
    private String lastName;

    @Parent
    private Person parent;

    //setter/getter/hashcode/equal...

结果:

person_idperson_addressfirst_namelast_name
1hangzhoulilei

方法二:

Person.java:

@Entity
@Table(name="person_embed")
public class Person {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer pId;

    @Column(name="person_address")
    private String pAddress;

    //映射组件
    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name="firstName",column=@Column(name="first_name")),
            @AttributeOverride(name="lastName",column=@Column(name="last_name"))
    })
    private Name pName;

    //setter/getter/hashcode/equal...

此时Name.java中不需要再使用@Embedded,只需要使用@Parent即可。

5.2 组件包含集合

映射的组件中又包含了集合,此时与entity类中直接包含集合完全一样,普通的集合映射
@Entity
@Table(name="person_embed_include_collection")
public class Person {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer pId;

    @Column(name="person_address")
    private String pAddress;

    //映射组件
    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name="firstName",column=@Column(name="first_name")),
        @AttributeOverride(name="lastName",column=@Column(name="last_name"))
    })
    private Name name;

    //setter/getter/hashcode/equal...

组件Name.java:

public class Name {

    private String firstName;


    private String lastName;

    @Parent
    private Person parent;

    //集合映射
    @ElementCollection(targetClass=Integer.class)
    @CollectionTable(name="person_power",joinColumns=@JoinColumn(name="person_id",
                     referencedColumnName="person_id",nullable=false))
    @MapKeyClass(value=String.class)
    @MapKeyColumn(name="power_name")
    @Column(name="power_number",nullable=false)
    private Map<String, Integer> power = new HashMap<String, Integer>();

    //setter/getter/hashcode/equal...

测试代码:

    Session session = HibernateUtils.getThreadLocalSession();
    Transaction tx = session.beginTransaction();

    Person p = new Person();
    p.setpAddress("shanghai");

    Name name = new Name();
    name.setFirstName("jack");
    name.setLastName("zhao");

    name.getPower().put("name-ZH",1);
    name.getPower().put("name-EN", 2);

    p.setName(name);

    session.persist(p);
    tx.commit();

结果:
person_embed_include_collection表:

person_idfirst_namelast_nameperson_address
1jackzhaoshanghai

person_power表:

person_idpower_numberpower_name
12name-EN
11name-ZH

5.3 集合中类型为组件

list、set中保存的元素为组件,map的value为组件,这个时候不需要使用@column修改集合,因为无法用一列保存所有的组件属性,其实就是用多列分别保存组件的各个属性,其它与保存普通类型变量完全一样

Person.java:

@Entity
@Table(name="person_collection_include_embed")
public class Person {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer pId;

    @Column(name="person_address")
    private String pAddress;

    //映射list中包含组件
    @ElementCollection(targetClass=Name.class)
    @CollectionTable(name="person_name_collection_include_embed",     
                     joinColumns=@JoinColumn(name="person_id",
                     referencedColumnName="person_id",nullable=false))
    @OrderColumn(name="list_order")
    private List<Name> names = new ArrayList<Name>();

    //映射map中包含组件
    @ElementCollection(targetClass=Score.class)
    @CollectionTable(name="person_score_collection_include_embed",
                     joinColumns=@JoinColumn(name="person_id",referencedColumnName="person_id",
                     nullable=false))
    @MapKeyClass(value=String.class)
    @MapKeyColumn(name="subject_name")
    private Map<String, Score> scores = new HashMap<String, Score>();

    //setter/getter/hashcode/equal...

组件Name.java:

@Embeddable
public class Name {

    @Column(name="first_name")
    private String first_name;

    @Column(name="last_name")
    private String last_name;

    @Parent
    private Person parent;

    //setter/getter/hashcode/equal...

组件Score.java:

@Embeddable
public class Score {

    @Column(name="score_level")
    private String score_level;

    @Column(name="score_mark")
    private Integer score_mark;

    @Parent
    private Person parent;

测试代码:

    Session session = HibernateUtils.getThreadLocalSession();
    Transaction tx = session.beginTransaction();

    Person p = new Person();
    p.setpAddress("beijing");

    Name name1 = new Name();
    name1.setFirst_name("ji");
    name1.setLast_name("mu");

    Name name2 = new Name();
    name2.setFirst_name("lucy");
    name2.setLast_name("zhang");

    p.getNames().add(name1);
    p.getNames().add(name2);

    Score score1 = new Score();
    score1.setScore_mark(96);
    score1.setScore_level("good");

    Score score2 = new Score();
    score2.setScore_mark(79);
    score2.setScore_level("so so");

    p.getScores().put("math", score1);
    p.getScores().put("english", score2);

    session.persist(p);

    tx.commit();

结果:
person_collection_include_embed表:

person_idperson_address
1beijing

person_name_collection_include_embed表:

person_idfirst_namelast_namelist_order
1jimu0
1lucyzhang1

person_score_collection_include_embed表:

person_idscore_levelscore_marksubject_name
1so so79english
1good96math

5.4 组件作为Map索引

5.5 组件作为主键

5.6 联合主键

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值