Hibernate学习笔记(黑马)--第三天(单数据源多表操作)

目录

第八章:多表设计

8.1 多表设计原则

8.2 数据库表格关系

8.3 数据库表和实体类的一对多关系

8.3.1 示例分析

8.3.2 表关系建立

8.3.3 实体类关系建立

8.4 数据库表和实体类多对多关系

8.4.1 示例分析

8.4.2 表关系建立

8.4.3 实体类关系建立

第九章:多表映射

9.1 一对多XML关系映射

9.1.1 客户配置文件:

9.1.2 联系人配置文件

9.2 多对多XML关系映射

9.2.1 用户配置文件:

9.2.2 角色配置文件:

第十章:多表增删改操作

10.1 一对多关系的操作

10.1.1 保存操作

10.1.2 修改操作

10.1.3 删除操作

10.2 多对多关系的操作

10.2.1 保存操作

10.2.2 删除操作

第十一章:多表查询操作

11.1 概述

11.2 对象导航检索示例

11.2.1 查询一个客户,获取该客户的所有联系人

11.2.2 查询一个联系人,获取该联系人的所有客户

11.3 对象导航查询的问题分析


第八章:多表设计

8.1 多表设计原则

在实际开发中,我们的数据库表难免会出现关联关系,在操作表时会涉及到多表操作。所以我们需要掌握配置实体之间(如用户实体和角色实体)的关联关系。

要实现多表映射,需要按照以下步骤:

  1. 确定两张表之间的关系(谁是一,谁是多);
  2. 在数据库中实现两表之间的关系;
  3. 在实体类中描述两者之间的关系(字段描述成属性,表格描述成对象);
  4. 配置实体类和数据库表的关系映射。(注解和XML方式)

8.2 数据库表格关系

数据库表格关系分为三种:一对一,一对多,多对多。

实际开发中,关联关系一般是一对多和多对多关系。实际开发中几乎不用一对一。

8.3 数据库表和实体类的一对多关系

8.3.1 示例分析

以客户类和联系人类为例:

客户:一般客户指一家公司

联系人:一般指客户的员工

客户和联系人的关系即为:一对多。

8.3.2 表关系建立

我们把一的一方称为主表,多的一方称为从表。数据库建立一对多的关系,就需要数据库的外键约束。

外键:指从表中的一列字段,取值参照主表主键。这一列就是外键。

外键的定义语法:

[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)

REFERENCES tbl_name (index_col_name, ...)

8.3.3 实体类关系建立

在实体类中,由于客户是一的一方,它应该包含多个联系人,所以实体类要体现出客户中有多个联系人的信息。代码如下:

/**
 * 客户的实体类
 */
public class Customer implements Serializable {

	private Long custId;
	private String custName;
	private String custSource;
	private String custIndustry;
	private String custLevel;
	private String custAddress;
	private String custPhone;
	
	//一对多关系映射:一个客户可以对应多个联系人
	private Set<LinkMan> linkmans = new HashSet<LinkMan>();
	
	public Long getCustId() {
		return custId;
	}
	public void setCustId(Long custId) {
		this.custId = custId;
	}
	public String getCustName() {
		return custName;
	}
	public void setCustName(String custName) {
		this.custName = custName;
	}
	public String getCustSource() {
		return custSource;
	}
	public void setCustSource(String custSource) {
		this.custSource = custSource;
	}
	public String getCustIndustry() {
		return custIndustry;
	}
	public void setCustIndustry(String custIndustry) {
		this.custIndustry = custIndustry;
	}
	public String getCustLevel() {
		return custLevel;
	}
	public void setCustLevel(String custLevel) {
		this.custLevel = custLevel;
	}
	public String getCustAddress() {
		return custAddress;
	}
	public void setCustAddress(String custAddress) {
		this.custAddress = custAddress;
	}
	public String getCustPhone() {
		return custPhone;
	}
	public void setCustPhone(String custPhone) {
		this.custPhone = custPhone;
	}
	public Set<LinkMan> getLinkmans() {
		return linkmans;
	}
	public void setLinkmans(Set<LinkMan> linkmans) {
		this.linkmans = linkmans;
	}
	@Override
	public String toString() {
		return "Customer [custId=" + custId + ", custName=" + custName + ", custSource=" + custSource
				+ ", custIndustry=" + custIndustry + ", custLevel=" + custLevel + ", custAddress=" + custAddress
				+ ", custPhone=" + custPhone + "]";
	}	
}

联系人类属于多的一方,每个联系人对应一个客户。

/**
 * 联系人的实体类(数据模型)
 */
public class LinkMan implements Serializable {

	private Long lkmId;
	private String lkmName;
	private String lkmGender;
	private String lkmPhone;
	private String lkmMobile;
	private String lkmEmail;
	private String lkmPosition;
	private String lkmMemo;

	//多对一关系映射:多个联系人对应客户
	private Customer customer;//用它的主键,对应联系人表中的外键
	
	public Long getLkmId() {
		return lkmId;
	}
	public void setLkmId(Long lkmId) {
		this.lkmId = lkmId;
	}
	public String getLkmName() {
		return lkmName;
	}
	public void setLkmName(String lkmName) {
		this.lkmName = lkmName;
	}
	public String getLkmGender() {
		return lkmGender;
	}
	public void setLkmGender(String lkmGender) {
		this.lkmGender = lkmGender;
	}
	public String getLkmPhone() {
		return lkmPhone;
	}
	public void setLkmPhone(String lkmPhone) {
		this.lkmPhone = lkmPhone;
	}
	public String getLkmMobile() {
		return lkmMobile;
	}
	public void setLkmMobile(String lkmMobile) {
		this.lkmMobile = lkmMobile;
	}
	public String getLkmEmail() {
		return lkmEmail;
	}
	public void setLkmEmail(String lkmEmail) {
		this.lkmEmail = lkmEmail;
	}
	public String getLkmPosition() {
		return lkmPosition;
	}
	public void setLkmPosition(String lkmPosition) {
		this.lkmPosition = lkmPosition;
	}
	public String getLkmMemo() {
		return lkmMemo;
	}
	public void setLkmMemo(String lkmMemo) {
		this.lkmMemo = lkmMemo;
	}	
	public Customer getCustomer() {
		return customer;
	}
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
	@Override
	public String toString() {
		return "LinkMan [lkmId=" + lkmId + ", lkmName=" + lkmName + ", lkmGender=" + lkmGender + ", lkmPhone="
				+ lkmPhone + ", lkmMobile=" + lkmMobile + ", lkmEmail=" + lkmEmail + ", lkmPosition=" + lkmPosition
				+ ", lkmMemo=" + lkmMemo + "]";
	}
}

接下来的问题就是:

在数据库中对客户实体的set集合和Customer实体对象建立关系关联。

8.4 数据库表和实体类多对多关系

8.4.1 示例分析

以用户类和角色类作为多对多关系分析。一个用户在不同场景中担任不同角色,一个角色对应的也不仅是一人。

8.4.2 表关系建立

多对多关系型数据库表的关联关系依靠中间表。用户对于中间表是一对多的关系,角色表对于中间表也是一对多的关系。

8.4.3 实体类关系建立

用户类:一个用户包含多个角色

/**
 *用户数据模型
 */
public class SysUser implements Serializable(){
    private Long userId;
    private String userCode;
    private String userName;
    private String userPassword;
    private String userState;
    
    //多对对关系映射
    private Set<SysRole> roles = new HashSet<SysRole>(0);//初始容量为0

    public Long getUserId() {
		return userId;
	}
	public void setUserId(Long userId) {
		this.userId = userId;
	}
	public String getUserCode() {
		return userCode;
	}
	public void setUserCode(String userCode) {
		this.userCode = userCode;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getUserPassword() {
		return userPassword;
	}
	public void setUserPassword(String userPassword) {
		this.userPassword = userPassword;
	}
	public String getUserState() {
		return userState;
	}
	public void setUserState(String userState) {
		this.userState = userState;
	}
	public Set<SysRole> getRoles() {
		return roles;
	}
	public void setRoles(Set<SysRole> roles) {
		this.roles = roles;
	}
	@Override
	public String toString() {
		return "SysUser [userId=" + userId + ", userCode=" + userCode + ", userName=" + userName + ", userPassword="
				+ userPassword + ", userState=" + userState + "]";
	}

}

角色可以赋予多个用户,角色类同样包含多个用户信息。

/**
 *角色类数据模型
 */
public class SysRole implements Serializable(){
    private Long roleId;
    private String roleName;
    private String roleMemo;
    
    //多对多关系映射
    private Set<SysUser> users = new HashSet<SysUser>(0);

    public Long getRoleId() {
		return roleId;
	}
	public void setRoleId(Long roleId) {
		this.roleId = roleId;
	}
	public String getRoleName() {
		return roleName;
	}
	public void setRoleName(String roleName) {
		this.roleName = roleName;
	}
	public String getRoleMemo() {
		return roleMemo;
	}
	public void setRoleMemo(String roleMemo) {
		this.roleMemo = roleMemo;
	}
	public Set<SysUser> getUsers() {
		return users;
	}
	public void setUsers(Set<SysUser> users) {
		this.users = users;
	}
	@Override
	public String toString() {
		return "SysRole [roleId=" + roleId + ", roleName=" + roleName + ", roleMemo=" + roleMemo + "]";
	}
}

第九章:多表映射

9.1 一对多XML关系映射

9.1.1 客户配置文件:

<?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.itheima.domain">
	<class name="Customer" table="cst_customer">
		<id name="custId" column="cust_id">
			<generator class="native"></generator>
		</id>
		<property name="custName" column="cust_name"></property>
		<property name="custLevel" column="cust_level"></property>
		<property name="custSource" column="cust_source"></property>
		<property name="custIndustry" column="cust_industry"></property>
		<property name="custAddress" column="cust_address"></property>
		<property name="custPhone" column="cust_phone"></property>
    
    <!--配置一对多关系映射)-->
    <!--set标签:用于映射set集合属性
            name属性:指定集合属性的名称
            table属性:在一对多的情况下写不写都行,指定集合元素对应的数据库表
    -->
    <set name="linkmans" table="cst_linkman">
        <!--one-to-many标签:用于指定当前映射配置文件对应的实体 和 set集合对应的实体 是一对多的关系
               class属性:set集合对应实体类名
        -->
        <one-to-many class="LinkMan"></one-to-many>
        <!--key标签:用于映射外键字段
              column属性:指定从表中外键字段名称
        -->
        <key column="lkm_cust_id"></key>
    </set>
</hibernate-mapping>

客户类不仅可以使用set集合关联LinkMan,还可以使用List,Map等集合。其对应的xml配置也随之变化。

9.1.2 联系人配置文件

<?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.itheima.domain">
	<class name="LinkMan" table="cst_linkman">
		<id name="lkmId" column="lkm_id">
			<generator class="native"></generator>
		</id>
		<property name="lkmName" column="lkm_name"></property>
		<property name="lkmGender" column="lkm_gender"></property>
		<property name="lkmPhone" column="lkm_phone"></property>
		<property name="lkmMobile" column="lkm_mobile"></property>
		<property name="lkmEmail" column="lkm_email"></property>
		<property name="lkmPosition" column="lkm_position"></property>
		<property name="lkmMemo" column="lkm_memo"></property>

    <!--多对一关系映射-->
    <!--
        many-to-one标签:用于建立多对一的关系映射配置
            name属性:指定的实体类中属性的名字,此处指customer属性
            class属性:该属性对应的实体类的名称。如果再hibernate-mapping上没有导包,则需要写全限定类名
            column属性:指定从表中外建字段名称
    -->
    <many-to-one name="customer" class="Class" column="lkm_cust_id"></many-to-one>
</hibernate-mapping>

9.2 多对多XML关系映射

9.2.1 用户配置文件:

<?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="cn.itcast.domain">
    <!--配置用户实体和用户数据库表的映射关系-->
    <class name="SysUser" table="sys_user">
        <id name="userId" column="user_id">
            <generator class="native"></generator>
        </id>
        <property name="userCode" column="user_code"></property>
        <property name="userName" column="user_name"></property>
        <property name="userPassword" column="user_password"></property>
        <property name="userState" column="user_state"></property>
    </class>
    
    <!--多对多关系映射-->
    <!--配置用户类和角色类的关联关系-->
    <!--set标签:用于映射set集合属性
            name属性:set集合名字 
            table属性:指定中间表名称,必须写
    -->
    <set name="roles" table="user_role_rel">
        <!--key标签:指定外键字段
                column属性:当前类在中间表中对应外键字段名称
        -->
        <key column="user_id"></key>
        <!--many-to-many标签:
                class属性:set集合元素对应的实体类名称
                column属性:set集合元素对应的实体类在中间表对应的外键字段
                
        -->
        <many-to-many class="SysRole" column="role_id"></many-to-many>
    </set>
</hibernate-mapping>

9.2.2 角色配置文件:

<?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="cn.itcast.domain">
    <!--配置实体类和数据库表的映射关系-->
    <class name="SysRole" table="sys_role">
        <id name="roleId" column="role_id">
            <generater class="native"></generater>
        </id>
        <property name="roleName" column="role_name"></property>
        <property name="roleMemo" column="role_memo"></property>
    </class>
    <!--配置多对多关联关系-->
    <set name="users" table="user_role_rel">
        <key column="role_id"></key>
        <many-to-many class="SysUser" cloumn="user_id"></many-to-many>
    </set>
</hibernate-mappign>

第十章:多表增删改操作

10.1 一对多关系的操作

10.1.1 保存操作

保存原则:先保存主表,在保存从表

/**
 *保存操作:
 *需求:保存一个客户和一个联系人
 *要求:
 *    1.创建一个客户和一个联系人对象
 *    2.建立客户和联系人的关联关系(一对多和多对一)
 *    3.先保存客户,在保存联系人
 *问题:
 *    在使用xml配置情况下:当我们建立了双向关联关系之后,先保存主表,再保存从表时:
 *    会产生两条insert和一条update,而我们只需要insert
 */
public void test1(){
		//创建客户和联系人对象
		Customer c = new Customer();//瞬时态
		c.setCustName("TBD云集中心");
		c.setCustLevel("VIP客户");
		c.setCustSource("网络");
		c.setCustIndustry("商业办公");
		c.setCustAddress("昌平区北七家镇");
		c.setCustPhone("010-84389340");
		
		LinkMan l = new LinkMan();//瞬时态
		l.setLkmName("TBD联系人");
		l.setLkmGender("male");
		l.setLkmMobile("13811111111");
		l.setLkmPhone("010-34785348");
		l.setLkmEmail("98354834@qq.com");
		l.setLkmPosition("老师");
		l.setLkmMemo("还行吧");

        //建立客户和联系人的双向关联关系
        c.getLinkMans().add(l);//获得客户对象的联系人属性,完成集合添加
        
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();

        //先保存客户,在保存联系人(先保存主表,在保存从表)
        s.save(c);
        s.save(l);

        tx.commit();//此时默认执行快照机制,当发现一级缓存和快照不一致时,使用一级缓存更新数据库
}

保存时遇见的一些问题: 

因为双方维护关联关系,且持久态对象可以自动更新数据库,更新客户的时候会修改一次外键,更新联系人的时候会再次更新一次外键,这样就会产生多余的SQL。解决方法很简单,只需要一方放弃维护权即可。也就是说关系不再有双方维护,而是由单方维护。通常我们会将维护权利交给多的一方。因为计算机系统更适合处理简单重复的事情。举个例子,一个老师对应多个学生(一对多),让老师记住所有学生的名字是很难的,但是让每个学生记住老师的名字是简单的。

让一方放弃外键维护权,配置方式如下:

cascade属性指明那些操作可以使用级联功能,即单方面修改后,系统自动对关联对象进行修改。

inverse属性默认值是false,即不放弃维护权。

10.1.2 修改操作

/**
 *修改操作:
 *需求:
 *    更新客户
 *要求:
 *    创建一个新的联系人对象,
 *    查询id为1的客户,
 *    建立联系人和客户的双向关联关系,
 *    更新客户
 *问题:
 *    当更新一个持久态对象时,它关联一个瞬时态对象。之行更新
 *    如果是注解配置:什么都不会做
 *    如果是xml配置:报错
 *解决办法:配置级联保存更新
 */
public void test2(){
    //创建新的联系人(瞬时态)
    LinkMan l = new LinkMan();
    l.setLkmName("TBD联系人test");
	l.setLkmGender("male");
	l.setLkmMobile("13811111111");
	l.setLkmPhone("010-34785348");
	l.setLkmEmail("98354834@qq.com");
	l.setLkmPosition("老师");
	l.setLkmMemo("还行吧");

    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    
    //查询id为1的客户
    Customer c1 = s.get(Customer.class,1L);
    //建立双向关联关系
    c1.getLinkMan().add(l);
    //更新客户
    s.update(c1);
    tx.commit();
}

修改中遇到的一些问题:

什么是级联操作:

级联操作就是当主控方执行保存、更新、或删除操作时,其关联对象(被控方)也执行相同的操作。在映射配置文件中通过对cascade属性对是否进行级联操作进行设置。

级联操作的方向性:

级联是有方向性的,所谓的方向性指的是,在保存一的一方级联多的一方和在保存多的一方级联一的一方。

此处我们需要保存客户,所以客户是主控方。那么就需要在客户的映射关系配置文件中进行如下配置:

解决报错的问题,配置级联保存更新:
<set name="linkmans" table="cst_linkman" cascade="save-update" inverse="true">
	<key column="lkm_cust_id"></key>
	<one-to-many class="LinkMan"/>
</set>

10.1.3 删除操作

/**
	 * 删除操作
	 * 	删除从表数据:可以随时任意删除。
	 * 	删除主表数据:
	 * 	    *有从表引用时:
	 *          1.默认情况下,会把外键字段设为null,然后删除主表数据;
	 *              当外键字段有非空约束时,系统报错
	 *          2.如果配置了放弃维护关联关系的权利,则不能进行删除(和非空约束无关,因为主表根本不会更新从表外键字段)
     *          3.如果还想删除,使用级联删除
	 *      *无从表引用:随便删除
	 * 
	 * 在实际开发中,级联删除请慎用!(在一对多的情况下)
	 */
	public void test3(){
		Session s = HibernateUtil.getCurrentSession();
		Transaction tx = s.beginTransaction();
		//查询id为1的客户
		Customer c1 = s.get(Customer.class, 2L);
		//删除id为1的客户
		s.delete(c1);
		tx.commit();
	}

 

10.2 多对多关系的操作

10.2.1 保存操作

需求:保存用户和角色

要求:创建2个用户和3个角色

           1号用户具有1号和2号角色(双向),

           2号用户具有2号和3号角色(双向),

           保存用户和角色。

问题:在保存时,会出现主键重复的错误,因为都要往中间表中保存数据。

解决办法:让任意一方放弃维护关联关系的权利。

public void test1(){
    //创建对象
    SysUser u1 = new SysUser();
    u1.setUserName("用户1");
    SysUser u2 = new SysUser();
    u1.setUserName("用户2");
    SysUser u3 = new SysUser();
    u1.setUserName("用户3");

    SysRole r1 = new SysRole();
    r1.setRoleName("角色1");
    SysRole r2 = new SysRole();
    r1.setRoleName("角色2");
    SysRole r3 = new SysRole();
    r1.setRoleName("角色3");

    //建立关联关系
    u1.getRoles().add(r1); 
    u1.getRoles().add(r2);
    r1.getUsers().add(u1);
    r2.getUsers().add(u1);
    
    u2.getRoles().add(r2);
    u2.getRoles().add(r3);
    r2.getUsers().add(u2);
    r3.getUsers().add(u2);

    //保存数据
    Session s = HibernateUtils.getCurrentSession();
    Transaction tx = s.beginTransaction();
    s.save(u1);
    s.save(u2);
    s.sava(r1);
    s.save(r2);
    s.save(r3);
    tx.commit();
}
解决保存失败的问题:
<set name="users" table="user_role_rel" inverse="true"><!--放弃维护权利-->
	<key column="role_id"></key>
	<many-to-many class="SysUser" column="user_id"></many-to-many>
</set>

10.2.2 删除操作

/**
	 * 删除操作
	 * 	在多对多的删除时,双向级联删除根本不能配置
	 * 禁用
	 *	如果配了的话,如果数据之间有相互引用关系,可能会清空所有数据
	 */
	@Test
	public void test2(){
		Session s = HibernateUtil.getCurrentSession();
		Transaction tx = s.beginTransaction();
		SysUser u1 = s.get(SysUser.class,3L);
		s.delete(u1);
		tx.commit();
	}

在映射配置中不能出现:双向级联删除的配置

第十一章:多表查询操作

11.1 概述

对象导航检索方式是根据已加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。

例如,我们通过OID查询方式查询一个客户,可以调用Customer类的getLinkMans()方法来获取客户的所有联系人。

对象导航查询使用要求:两个对象之间必须存在关联关系。

11.2 对象导航检索示例

11.2.1 查询一个客户,获取该客户的所有联系人

/**
 *需求:查询id为1的客户有多少联系人
 */
public void test1(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    Customer c = s.get(Customer.class,1L);
    Set<LinkMan> linkMans = c.getLinkMans();//此处就是对象导航查询
    for(Object o : linkMans){
        System.out.println(o);
    }
    tx.commit();
}

11.2.2 查询一个联系人,获取该联系人的所有客户

/**
 *需求:查询id为1的联系人有多少客户
 */
public void test2(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    LinkMan l = s.get(LinkMan.class,1L);
    Set<Customer> customers = c.getCustomers();//此处就是对象导航查询
    for(Object o : customers){
        System.out.println(o);
    }
    tx.commit();
}

11.3 对象导航查询的问题分析

问题1:查询客户时,需不需要将联系人都查询出来?

方案:

一个客户关联多个联系人,在用不到的情况下查询出来会加大内存消耗。我们可以利用延迟加载的思想,当我们需要联系人信息时,再进行联系人数据加载。

配置方式

在Customer.hbm.xml配置文件中的set标签上使用lazy属性。取值为true(默认值)|fasle
<set name="linkmans" table="cst_linkman" inverse="true" lazy="true">
	<key column="lkm_cust_id"></key>
	<one-to-many class="LinkMan"/>
</set>

问题2:查询联系人时,需不需要将客户都查询出来?

方案:

一个联系人只关联一个客户,一个对象对内存的消耗并不大,且多数场景我们需要用到该对象,所以一般立即查询出来。

配置方式:

在LinkMan.hbm.xml配置文件中的many-to-one标签上使用lazy属性。取值为proxy|fasle
false:立即加载
proxy:看客户的映射文件class标签的lazy属性取值,如果客户的class标签lazy属性是true
	   那么proxy表示延迟加载,如果是false就表示立即加载。
<many-to-one name="customer" class="Customer" column="lkm_cust_id" lazy="false"/>

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值