[ SSH框架 ] Hibernate框架学习之三

一、表关系的分析

  Hibernate框架实现了ORM的思想,将关系数据库中表的数据映射成对象,使开发人员把对数据库的操作转化为对对象的操作,Hibernate的关联关系映射主要包括多表的映射配置、数据的增加、删除等。   数据库中多表之间存在着三种关系,也就是系统设计中的三种实体关系。如图所示。

 从图可以看出,系统设计的三种实体关系分别为:多对多、一对多和一对一关系。在数据库中实体表之间的关系映射是采用外键来描述的,具体如下。

1.1 表与表的三种关系

●  一对多

建表原则:再多的一方创建外键指向一的一方的主键:

●  多对多

建表原则:创建一个中间表,中间表中至少两个字段作为外键分别指向多对多双方的主键

●  一对一

建表原则(两种):①  唯一外键对应:假设一对一中的任意一方为多,在多的一方创建外键指向一的一方的主键,然后将外键设置为唯一。

            ②  主键对应:一方的主键作为另一方的主键。

数据库表能够描述的实体数据之间的关系,通过对象也可以进行描述,所谓的关联映射就是将关联关系映射到数据库里,在对象模型中就是一个或多个引用。在 Hibernate中采用Java对象关系来描述数据表之间的关系,具体如图所示。

  从图可以看出,通过一对一的关系就是在本类中定义对方类型的对象,如A中定义B类类型的

属性b,B类中定义A类类型的属性a:一对对多的关系,图中描述的是一个A对应多个B类类型的

情况,需要在A类以Set集合的方式引入B类型的对象,在B类中定义A类类型的属性a;多对多

的关系,在A类中定义B类类型的Set集合,在B类中定义A类类型的Set集合,这里用Set集合

的目的是避免了数据的重复。

  以上就是系统模型中实体设计的三种关联关系,由于一对一的关联关系在开发中不常使用,所以我们不单独讲解,了解即可。那么接下来我们就先来学习一下一对多的关系映射。

二、Hibernate 一对多关系映射

2.1创建表

联系人表中存在外键(lkm_cust_id),外键指向客户表,表示如下图:

2.2 创建实体:

客户实体:

package com.Kevin.domain;
/**
 * 创建客户实体类
 *  
 */

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

public class Customer implements Serializable {
    private Long cust_id;
    private String cust_name;
    private String cust_address;    
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_phone;
    private String cust_mobile;
    
    private Set<Linkman> linkmans=new HashSet<Linkman>(0);
    
    //一对多关系映射:多的一方
    //主表实体应该包含从表实体的集合引用
    public Set<Linkman> getLinkmans() {
        return linkmans;
    }
    public void setLinkmans(Set<Linkman> linkmans) {
        this.linkmans = linkmans;
    }
    public Long getCust_id() {
        return cust_id;
    }
    public void setCust_id(Long cust_id) {
        this.cust_id = cust_id;
    }
    public String getCust_address() {
        return cust_address;
    }
    public void setCust_address(String cust_address) {
        this.cust_address = cust_address;
    }
    public String getCust_name() {
        return cust_name;
    }
    public void setCust_name(String cust_name) {
        this.cust_name = cust_name;
    }
    public String getCust_source() {
        return cust_source;
    }
    public void setCust_source(String cust_source) {
        this.cust_source = cust_source;
    }
    public String getCust_industry() {
        return cust_industry;
    }
    public void setCust_industry(String cust_industry) {
        this.cust_industry = cust_industry;
    }
    public String getCust_level() {
        return cust_level;
    }
    public void setCust_level(String cust_level) {
        this.cust_level = cust_level;
    }
    public String getCust_phone() {
        return cust_phone;
    }
    public void setCust_phone(String cust_phone) {
        this.cust_phone = cust_phone;
    }
    public String getCust_mobile() {
        return cust_mobile;
    }
    public void setCust_mobile(String cust_mobile) {
        this.cust_mobile = cust_mobile;
    }
    @Override
    public String toString() {
        return "Customer [cust_id=" + cust_id + ", cust_address=" + cust_address + ", cust_name=" + cust_name
                + ", cust_source=" + cust_source + ", cust_industry=" + cust_industry + ", cust_level=" + cust_level
                + ", cust_phone=" + cust_phone + ", cust_mobile=" + cust_mobile + "]";
    }
    
    

}

联系人实体:

package com.Kevin.domain;
/**
 * 创建联系人实体类
 *  
 */
import java.io.Serializable;

public class Linkman implements Serializable {
    private Long lkm_id;
    private String lkm_name;
    private String lkm_gender;
    private String lkm_mobile;
    private String lkm_phone;
    private String lkm_email;
    private String lkm_qq;
    private String lkm_position;
    private String lkm_memo;
    
    //一对多关系影射
    //从表实体包含主表实体的对象引用
    private Customer customer;
    
    
    public Customer getCustomer() {
        return customer;
    }
    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
    public Long getLkm_id() {
        return lkm_id;
    }
    public void setLkm_id(Long lkm_id) {
        this.lkm_id = lkm_id;
    }
    public String getLkm_name() {
        return lkm_name;
    }
    public void setLkm_name(String lkm_name) {
        this.lkm_name = lkm_name;
    }
    public String getLkm_gender() {
        return lkm_gender;
    }
    public void setLkm_gender(String lkm_gender) {
        this.lkm_gender = lkm_gender;
    }
    public String getLkm_mobile() {
        return lkm_mobile;
    }
    public void setLkm_mobile(String lkm_mobile) {
        this.lkm_mobile = lkm_mobile;
    }
    public String getLkm_phone() {
        return lkm_phone;
    }
    public void setLkm_phone(String lkm_phone) {
        this.lkm_phone = lkm_phone;
    }
    public String getLkm_email() {
        return lkm_email;
    }
    public void setLkm_email(String lkm_email) {
        this.lkm_email = lkm_email;
    }
    public String getLkm_qq() {
        return lkm_qq;
    }
    public void setLkm_qq(String lkm_qq) {
        this.lkm_qq = lkm_qq;
    }
    public String getLkm_position() {
        return lkm_position;
    }
    public void setLkm_position(String lkm_position) {
        this.lkm_position = lkm_position;
    }
    public String getLkm_memo() {
        return lkm_memo;
    }
    public void setLkm_memo(String lkm_memo) {
        this.lkm_memo = lkm_memo;
    }
    @Override
    public String toString() {
        return "Linkman [lkm_id=" + lkm_id + ", lkm_name=" + lkm_name + ", lkm_gender=" + lkm_gender + ", lkm_mobile="
                + lkm_mobile + ", lkm_phone=" + lkm_phone + ", lkm_email=" + lkm_email + ", lkm_qq=" + lkm_qq
                + ", lkm_position=" + lkm_position + ", lkm_memo=" + lkm_memo + "]";
    }
    
    

}

2.3 创建映射

客户映射:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
创建客户类关系映射
导入dtd约束
 -->
 <!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 
    private Long cust_id;
    private String cust_address;
    private String cust_name;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_phone;
    private String cust_mobile;
 -->    
<hibernate-mapping package="com.Kevin.domain">
    <class name="Customer" table="cust_customer" lazy="false">
        <id name="cust_id">
            <generator class="native"></generator>
        </id>
        <property name="cust_name" column="cust_name"></property>
        <property name="cust_address" column="cust_address"></property>
        <property name="cust_source" column="cust_source"></property>
        <property name="cust_industry" column="cust_industry"></property>
        <property name="cust_level" column="cust_level"></property>
        <property name="cust_phone" column="cust_phone"></property>
        <property name="cust_mobile" column="cust_mobile"></property>
        
        <!-- 一对多关系影射:主表实体的映射配置
            涉及的标签:set:用于配置set集合属性
                            属性:name:指定实体类中set集合的属性名称
                                  table:指定从表的名称,在一对多配置时可以不写
                        key:用于映射外键字段
                            属性:column:指定外键字段名称
                        one—to—many:用于建立一对多的映射配置
                            属性:class:指定从表实体类的名称                  
         -->
        <set name="linkmans" table="cust_linkman" >
            <key column="lkm_cust_id"></key>
            <one-to-many class="Linkman"/>
        </set>
    </class>
</hibernate-mapping>

使用set集合来描述 Customer.java类中的属性 linkman。在 Hibernate的映射文件中,使用<set>标签用来描述被映射类中的Set集合,<key>标签的 column 属性值对应文件多的一方的外键名称,在 Customer.java客户类中,客户与联系人是一对多的关系,,Hibernate的映射文件中,使用< one-to-many>标签来描述持久化类的一对多关联,其中 class属性用来描述映射的关联类。

联系人映射:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
创建联系人实体类映射
导入dtd约束
 -->
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
<!-- 
    private Long lkm_id;
    private String lkm_name;
    private String lkm_gender;
    private String lkm_mobile;
    private String lkm_phone;
    private String lkm_email;
    private String lkm_qq;
    private String lkm_position;
    private String lkm_memo;
 --> 
<hibernate-mapping package="com.Kevin.domain">
    <class name="Linkman" table="cust_linkman">
        <id name="lkm_id">
            <generator class="native"></generator>
        </id>
        <property name="lkm_name" column="lkm_name"></property>
        <property name="lkm_gender" column="lkm_gender"></property>
        <property name="lkm_mobile" column="lkm_mobile"></property>
        <property name="lkm_phone" column="lkm_phone"></property>
        <property name="lkm_email" column="lkm_email"></property>
        <property name="lkm_qq" column="lkm_qq"></property>
        <property name="lkm_position" column="lkm_position"></property>
        <property name="lkm_memo" column="lkm_memo"></property>
        
        <!-- 一对多关系影射:从表实体的映射配置
            涉及的标签:many-to-one:建立多对一的映射配置
                                属性:name:从表示实体中引用主表实体对象的引用的名称
                                      class:指定属性所对应的实体类名称        
         -->
        <many-to-one name="customer" class="Customer" column="lkm_cust_id" ></many-to-one>
    </class>
</hibernate-mapping> 

  <many-to-one>标签定义两个持久化类的关联,这种关联是数据表间的多对一关联,联系人与客户就是多对一的关系,所以用< many-to-one>标签来描述。<many-to-one>标签的name属性用来描述 customer在 Linkman.java类中的属性的名称,class属性用来指定映射的类,column属性值对应表中的外键列名。

2.4 将映射添加到配置文件

        <mapping resource="com/Kevin/domain/Linkman.hbm.xml"/>
        <mapping resource="com/Kevin/domain/Customer.hbm.xml"/>

2.5 编写测试代码

  @Test
    public void test2(){
        Session s=HibernateUtil.getCurrSession();
        Transaction tx=s.beginTransaction();
        
        //1.创建一个客户
        Customer c1=new Customer();   //瞬时态
        c1.setCust_name("Kevin_one2many");
        //2.创建一个新的联系人
        Linkman lkm1=new Linkman();   //瞬时态
        lkm1.setLkm_name("Kevin_one2many1");
        Linkman lkm2=new Linkman();   //瞬时态
        lkm2.setLkm_name("Kevin_one2many2");
        //3.建立客户和联系人的关联关系(让双向)
        lkm1.setCustomer(c1);
        lkm2.setCustomer(c1);
        c1.getLinkmans().add(lkm1);
        c1.getLinkmans().add(lkm2);
        //4.保存要符合原则
        s.save(c1);         //持久态 有一级缓存和快照
        s.save(lkm1);    //持久态 有一级缓存和快照
        s.save(lkm2);
        tx.commit();
    }

  在配置文件中添加了自动建表信息后,运行程序时,程序会自动创建两张表,并且插入数据。运行方法后,控制台输出结果如所示:

 从图的输出结果可以看到,控制台成功输出了三条insert语句和两条update语句,此时查询数据库中的数据如图所示:

  从上图的查询结果可以看出,数据表创建成功,并成功插入了相应的数据。那么一个基本的一对多的关联关系映射就已经配置好了。从以上代码我们可以发现我们建立的关系是双向的,即客户关联了联系人,同时联系人也关联了客户。

三、一对多的相关操作

  级联操作是指当主控方执行保存、更新或者删除操作时,其关联对象(被控方)也执行相同的操作。在映射文件中通过对 cascade属性的设置来控制是否对关联对象采用级联操作,级联操作对各种关联关系都是有效的。

3.1 级联保存或更新

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

保存客户级联联系人   首先要确定我们要保存的主控方是那一方,我们要保存客户,所以客户是主控方,那么需要在客户的映射文件中进行如下的配置。

<!-- 一对多关系影射:主表实体的映射配置
            涉及的标签:set:用于配置set集合属性
                            属性:name:指定实体类中set集合的属性名称
                                  table:指定从表的名称,在一对多配置时可以不写
                        key:用于映射外键字段
                            属性:column:指定外键字段名称
                        one—to—many:用于建立一对多的映射配置
                            属性:class:指定从表实体类的名称        
                                
         -->
        <set name="linkmans" table="cust_linkman" cascade="save-update">
            <key column="lkm_cust_id"></key>
            <one-to-many class="Linkman"/>
        </set>

然后可以编写如下测试代码:

@Test
    public void test(){
        Session s=HibernateUtil.getCurrSession();
        Transaction tx=s.beginTransaction();
        
        //1.创建一个客户
        Customer c1=new Customer();   //瞬时态
        c1.setCust_name("Kevin");
        //2.创建一个新的联系人
        Linkman lkm1=new Linkman();   //瞬时态
        lkm1.setLkm_name("Kevin_one2many");
        //3.建立客户和联系人的关联关系(让双向)
        lkm1.setCustomer(c1);
        c1.getLinkmans().add(lkm1);
        //4.保存要符合原则
        s.save(c1);         //持久态 有一级缓存和快照
        tx.commit();
    }

保存联系人级联客户

  同样我们需要确定主控方,现在我们的主控方是联系人。所以需要在联系人的映射文件中进行配置,内容如下:

<!-- 一对多关系影射:从表实体的映射配置
            涉及的标签:many-to-one:建立多对一的映射配置
                                属性:name:从表示实体中引用主表实体对象的引用的名称
                                      class:指定属性所对应的实体类名称                                         
 -->
 <many-to-one name="customer" class="Customer" column="lkm_cust_id" cascade="save-update"></many-to-one>

编写如下测试代码:

@Test
    public void test(){
        Session s=HibernateUtil.getCurrSession();
        Transaction tx=s.beginTransaction();
        
        //1.创建一个客户
        Customer c1=new Customer();   //瞬时态
        c1.setCust_name("Kevin");
        //2.创建一个新的联系人
        Linkman lkm1=new Linkman();   //瞬时态
        lkm1.setLkm_name("Kevin_one2many");
        //3.建立客户和联系人的关联关系(让双向)
        lkm1.setCustomer(c1);
        c1.getLinkmans().add(lkm1);
        //4.保存要符合原则
        s.save(lkm1);         //持久态 有一级缓存和快照
        tx.commit();
    }

3.2 级联更新

    @Test
    public void test5(){
        Session s=HibernateUtil.getCurrSession();
        Transaction tx=s.beginTransaction();
        
        //1.查询一个客户
        Customer c1=s.get(Customer.class, 1l);
        //2.创建一个新的联系人
        Linkman lkm=new Linkman(); //瞬时态
        lkm.setLkm_name("one2many_update");
        //3.建立客户和联系人的关联关系(双向)
        lkm.setCustomer(c1);
        c1.getLinkmans().add(lkm);
        //4.更新联系人
        s.update(c1);
        tx.commit();
    }

3.3 Hibernate 的级联删除

 我们之前学习过级联保存或更新,那么再来看级联删除也就不难理解了,级联删除也是有方向性的,删删除客户同时级联删除联系人,也可以删除联系人同时级联删除客户(这种需求很少)。

  原来JDBC中删除客户和联系人的时候,如果有外键的关系是不可以删除的,但是现在我们使用了 Hibernate,其实 Hibernate可以实现这样的功能,但是不会删除客户同时删除联系人,默认情况下 Hibernate会怎么做呢呢?我们们来看下面的测试:

    @Test 
    public void test6(){
        Session s=HibernateUtil.getCurrSession();
        Transaction tx =s.beginTransaction();
        
        Customer c=s.get(Customer.class, 71);
        //删除客户
        s.delete(c);
        tx.commit();
    }

默认的情况下如果客户下面还有联系人,,Hibernate会将联系人的外键置为null,然后去删除客户。那么其实有的时候我们需要删除客户的时候,同时将客户关联的联系人一并删除。这个时候我们就需要使用 Hibernate的级联保存操作了。

删除客户的时候同时删除客户的联系人 确定删除的主控方式客户,所以需要在客户端配置:

        <set name="linkmans" table="cust_linkman" cascade="save-update,delete">
            <key column="lkm_cust_id"></key>
            <one-to-many class="Linkman"/>
        </set>

编写如下测试代码:

    @Test 
    public void test6(){
        Session s=HibernateUtil.getCurrSession();
        Transaction tx =s.beginTransaction();
        
        Customer c=s.get(Customer.class, 7l);
        //删除客户
        s.delete(c);
        tx.commit();
    }

3.4 双向关联产生多余的SQL语句

  之前已经分析过了,因为双向维护了关系,而且持久态对象可以自动更新数据库,更新客户的时候会修改一次外键,更新联系人的时候同样也会修改一次外键。这样就会产生了多余的SQL语句,那么问题产生了,我们又该如何解决呢?其实解决的办法很简单,只需要将一方放弃外键维护权即可。也就是说关系不是双方维护的,只需要交给某一方去维护就可以了。通常我们都是交给多的一方去维护的。为什么呢?因为多的方才是维护关系的最好的地方。举个例子,一个老师对应多个学生,一个学生对应一个老师,这是典型的一对多。那么一个老师如果要记住所有学生的名字很难的,但如果让每个学生记住老师的名字应该不难。其实就是这个道理。所以在一对多中,一的一方都会放弃外键的维护权(关系的维护)。

  这个时候如果想让一的一方放弃外键的维护权,只需要进行如下的配置即可。

  inverse的默认值是false ,代表不放弃外键维护权,配置值为true,代表放弃了外键的维护权。此时就不会再产生之前的问题。

四、Hibernate的多对多关联关系映射

4.1 创建表

数据模型如下:

4.2 创建实体

 用户实体:

package com.Kevin.domain;
/**
 * 用户实体类
 */

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

public class SysUser implements Serializable {
    private Long userId;
    private String userName;
    private String userPassword;
    private Integer userState;
    //多对多关系映射:
    private Set<SysRole> roles=new HashSet<SysRole>(0);
    
    public Set<SysRole> getRoles() {
        return roles;
    }
    public void setRoles(Set<SysRole> roles) {
        this.roles = roles;
    }
    public Long getUserId() {
        return userId;
    }
    public void setUserId(Long userId) {
        this.userId = userId;
    }
    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 Integer getUserState() {
        return userState;
    }
    public void setUserState(Integer userState) {
        this.userState = userState;
    }
    @Override
    public String toString() {
        return "SysUser [userId=" + userId + ", userName=" + userName + ", userPassword=" + userPassword
                + ", userState=" + userState + "]";
    }
    

}

角色实体:

package com.Kevin.domain;
/**
 * 角色的实体类
 */

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

public class SysRole implements Serializable {
    private Long roleId;
    private String roleName;
    private String roleMemo;
    //多对多关系映射:一个角色可以赋予多个用户
    private Set<SysUser> users=new HashSet<SysUser>(0);
    
    public Set<SysUser> getUsers() {
        return users;
    }
    public void setUsers(Set<SysUser> users) {
        this.users = users;
    }
    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;
    }
    @Override
    public String toString() {
        return "SysRole [roleId=" + roleId + ", roleName=" + roleName + ", roleMemo=" + roleMemo + "]";
    }
    

}

4.3 创建映射

用户映射:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
创建用户类关系映射
导入dtd约束
 -->
 <!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 
    private Long userId;
    private String userName;
    private String userPassword;
    private Integer userState;
 -->    
<hibernate-mapping package="com.Kevin.domain">
    <class name="SysUser" table="sys_user" >
        <id name="userId" column="user_id">
            <generator class="native"></generator>
        </id>
        <property name="userName" column="user_name"></property>
        <property name="userPassword" column="user_password"></property>
        <property name="userState" column="user_state"></property>
        <!-- 
            多对多关系映射涉及的标签:
                set:用于映射set集合属性
                    name:指定集合名称
                    table:指定中间表的名称
                key:用于映射外键字段
                    column:指定当前实体在中间表的外键字段名称
                many-to-many:用于映射多对多的关系
                    class:对方的实体类
                    column:    对方在中间类的外键字段名称
         -->
         <set name="roles" table="user_role_ref" inverse="true" cascade="delete">
             <key column="user_id"></key>
             <many-to-many class="SysRole" column="role_id" />
         </set>
    </class>
</hibernate-mapping>

角色映射:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
创建用户类关系映射
导入dtd约束
 -->
 <!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 
    private Long roleId;
    private String roleName;
    private String roleMemo;
 -->    
<hibernate-mapping package="com.Kevin.domain">
    <class name="SysRole" table="sys_role" >
        <id name="roleId" column="role_id">
            <generator class="native"></generator>
        </id>
        <property name="roleName" column="role_name"></property>
        <property name="roleMemo" column="role_memo"></property>
                <!-- 
            多对多关系映射涉及的标签:
                set:用于映射set集合属性
                    name:指定集合名称
                    table:指定中间表的名称
                key:用于映射外键字段
                    column:指定当前实体在中间表的外键字段名称
                many-to-many:用于映射多对多的关系
                    class:对方的实体类
                    column:    对方在中间类的外键字段名称
         -->
         <set name="users" table="user_role_ref" cascade="delete">
             <key column="role_id"></key>
             <many-to-many class="SysUser" column="user_id"/>
         </set>
    </class>
</hibernate-mapping>

4.4 在核心配置中加入映射文件

        <mapping resource="com/Kevin/domain/SysUser.hbm.xml"/>
        <mapping resource="com/Kevin/domain/SysRole.hbm.xml"/>

4.5 编写测试类

    /**
     * 保存操作:需求:创建2个用户和3个角色
     *                     让1号用户具备1号和2号角色
     *                     让2号用户具备2号和3号角色
     *                     保存用户和角色
     */
    @Test
    public void test(){
        SysUser u1=new SysUser();
        u1.setUserName("User1");
        SysUser u2=new SysUser();
        u2.setUserName("User2");
        
        SysRole r1=new SysRole();
        r1.setRoleName("Role1");
        SysRole r2=new SysRole();
        r2.setRoleName("Role2");
        SysRole r3=new SysRole();
        r3.setRoleName("Role3");
        
        //建立双相关联关系
        //先建立用户
        u1.getRoles().add(r1);
        u1.getRoles().add(r2);
        u2.getRoles().add(r2);
        u2.getRoles().add(r3);
        //建立角色
        r1.getUsers().add(u1);
        r2.getUsers().add(u1);
        r2.getUsers().add(u2);
        r3.getUsers().add(u2);
        
        Session s=HibernateUtil.getCurrSession();
        Transaction tx=s.beginTransaction();
        
        s.save(u1);
        s.save(u2);
        s.save(r1);
        s.save(r2);
        s.save(r3);
        tx.commit();
    }

五、多对多的相关操作

5.1 级联保存或更新

  之前已经学习过一对多的级联保存了,那么多对多也是一样的。如果只保存单独的一方是不可以的,还是需要保存双方的。如果就想保存一方就需要设置级联操作。同样要看保存的主控方是哪一端,就需要在那一端进行配置。

保存用户级联角色

编写测试代码:

/**
     * 级联保存操作:
     * 需求:创建2个用户和3个角色
     *                     让1号用户具备1号和2号角色
     *                     让2号用户具备2号和3号角色
     *                     保存用户和角色
     */
    @Test
    public void test1(){
        SysUser u1=new SysUser();
        u1.setUserName("User1");
        SysUser u2=new SysUser();
        u2.setUserName("User2");
        
        SysRole r1=new SysRole();
        r1.setRoleName("Role1");
        SysRole r2=new SysRole();
        r2.setRoleName("Role2");
        SysRole r3=new SysRole();
        r3.setRoleName("Role3");
        
        //建立双相关联关系
        //先建立用户
        u1.getRoles().add(r1);
        u1.getRoles().add(r2);
        u2.getRoles().add(r2);
        u2.getRoles().add(r3);
        //建立角色
        r1.getUsers().add(u1);
        r2.getUsers().add(u1);
        r2.getUsers().add(u2);
        r3.getUsers().add(u2);
        
        Session s=HibernateUtil.getCurrSession();
        Transaction tx=s.beginTransaction();
        
        s.save(u1);
        s.save(u2);
        tx.commit();
    }

 保存角色级联用户

编写测试代码:

/**
     * 级联保存操作:保存角色级联用户
     * 需求:创建2个用户和3个角色
     *                     让1号用户具备1号和2号角色
     *                     让2号用户具备2号和3号角色
     *                     保存用户和角色
     */
    @Test
    public void test3(){
        SysUser u1=new SysUser();
        u1.setUserName("User1");
        SysUser u2=new SysUser();
        u2.setUserName("User2");
        
        SysRole r1=new SysRole();
        r1.setRoleName("Role1");
        SysRole r2=new SysRole();
        r2.setRoleName("Role2");
        SysRole r3=new SysRole();
        r3.setRoleName("Role3");
        
        //建立双相关联关系
        //先建立用户
        u1.getRoles().add(r1);
        u1.getRoles().add(r2);
        u2.getRoles().add(r2);
        u2.getRoles().add(r3);
        //建立角色
        r1.getUsers().add(u1);
        r2.getUsers().add(u1);
        r2.getUsers().add(u2);
        r3.getUsers().add(u2);
        
        Session s=HibernateUtil.getCurrSession();
        Transaction tx=s.beginTransaction();
        s.save(r1);
        s.save(r2);
        s.save(r3);
        tx.commit();
    }

5.2 级联删除(了解)

   级联删除仅作了解,因为在实际开发中是禁止用的。由于在多对多关联关系下,往往有多个对象是关联的,因此只要删除一个,使用级联操作,就会删除多个对象和数据。

测试代码:

    /**
     * 删除操作
     * 在实际开发中:多对多的双向级联删除是禁止使用的
     */
    @Test
    public void test2(){
        Session s=HibernateUtil.getCurrSession();
        Transaction tx=s.beginTransaction();
        
        SysUser u1=s.get(SysUser.class, 1l);
        
        s.delete(u1);
        tx.commit();
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏农夫安全

代码审计之SQL注入漏洞

SQL注入: 我的理解很简单,能代入到数据库查询,且没有过滤,或过滤不严谨,就可以造成SQL注入 演示环境:linux+apache+...

37370
来自专栏更流畅、简洁的软件开发方式

预防SQL注入攻击之我见

1、 SQL注入攻击的本质:让客户端传递过去的字符串变成SQL语句,而且能够被执行。 2、 每个程序员都必须肩负起防止SQL注入攻击的责任。   说起防止SQ...

53560
来自专栏技术碎碎念

sql server存储过程编程

存储过程是一组完成特定功能的SQL 语句集合,经编译后存储在数据库中。 存储过程作为一个单元进行处理并以一个名称来标识。它能向用户返回数据、向数据库表中写入或修...

43160
来自专栏DOTNET

Entity Framework——性能测试

内容提要 一、对EF框架的性能测试 增、删、改,查测试及性能优化 二、使用sql执行 增、删、改,查测试 三、对以上两种方式对比分析 一 对EF框架的测试 1...

73660
来自专栏PingCAP的专栏

TiDB 源码阅读系列文章(六)Select 语句概览

Select 语句只会讲解最简单的情况:全表扫描+过滤,暂时不考虑索引等复杂情况,更复杂的情况会在后续章节中介绍。语句为:

50780
来自专栏逸鹏说道

SQL Server 存储过程的几种常见写法分析

最近发现还有不少做开发的小伙伴,在写存储过程的时候,在参考已有的不同的写法时,往往很迷茫, 不知道各种写法孰优孰劣,该选用那种写法,以及各种写法优缺点,本文以一...

43280
来自专栏后台架构

Sphinx源码学习笔记(一):索引创建

  因为项目开发需要在游戏内部实现玩家名称的模糊查找功能,本身直接使用Sphinx配置mysql可以直接搭建一套模糊匹配的即可支持功能的实现。

52070
来自专栏用户画像

mysql模拟题二

  3) MSSQLServer2005Enterprise Edition是哪一种版本?

10860
来自专栏陈本布衣

SQLite 带你入门

SQLite数据库相较于我们常用的Mysql,Oracle而言,实在是轻量得不行(最低只占几百K的内存)。平时开发或生产环境中使用各种类型的数据库,可能都需要...

45050
来自专栏Java帮帮-微信公众号-技术文章全总结

高级框架-springDate-JPA 第二天【悟空教程】

通过annotation(注解)来映射实体类和数据库表的对应关系,基于annotation的主键标识为@Id注解, 其生成规则由@GeneratedValue ...

22710

扫码关注云+社区

领取腾讯云代金券