JavaWeb - Hibernate框架使用(三)

表与表的关系

关键是维护关联属性

一对多|多对一

一对多(多对一):

  • 数据表中:

客户表

cid cname
1 百度
2 网易

​ 联系人表

lid lname cid
1 张总 1
2 刘总 1
3 王总 2
  • 实体中:

    客户(Cudtomer)实体:

    private Long cid;
    private String cname;
    //使用集合表达‘一’的一方拥有多个‘多’的一方
    private Set<LinkMan> linkMen;
    

    联系人(LinkMan)实体:

    private Long lid;
    private String lname;
    //使用对象引用‘一’的一方表达‘多’的一方属于哪个‘一’的一方
    private Customer customer;
    
  • orm元数据中:

    Customer.hbm.xml中(‘一’的一方):

      <class name="Customer" table="cst_customer" >
          <id name="cust_id"  >
              <generator class="native"></generator>
          </id>
          <property name="cust_name" column="cust_name" ></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_linkman" column="cust_linkman" ></property>
          <property name="cust_phone" column="cust_phone" ></property>
          <property name="cust_mobile" column="cust_mobile" ></property>
      
          <!-- 集合,一对多关系,在配置文件中配置 -->
          <!-- 
              name属性:集合属性名
              column属性: 外键列名
              class属性: 与我关联的对象完整类名
           -->
           <!-- 
              级联操作:   cascade
                  save-update: 级联保存更新
                  delete:级联删除
                  all:save-update+delete
              级联操作: 简化操作.目的就是为了少些两行代码.
            -->
            <!-- inverse属性: 配置关系是否维护. 
                  true: customer不维护关系
                  false(默认值): customer维护关系
    
              inverse属性: 性能优化.提高关系维护的性能.
              原则: 无论怎么放弃,总有一方必须要维护关系.
              一对多关系中: 一的一方放弃.也只能一的一方放弃.多的一方不能放弃.
            -->
          <set name="linkMens" inverse="true" cascade="delete"  >
              <key column="lkm_cust_id" ></key>
              <one-to-many class="LinkMan" />
          </set>
      </class>
    

    LinkMan.hbm.xml中(‘多’的一方):

      <class name="LinkMan" table="cst_linkman" >
          <id name="lkm_id"  >
              <generator class="native"></generator>
          </id>
          <property name="lkm_gender"  ></property>
          <property name="lkm_name"  ></property>
          <property name="lkm_phone"  ></property>
          <property name="lkm_email"  ></property>
          <property name="lkm_qq"  ></property>
          <property name="lkm_mobile"  ></property>
          <property name="lkm_memo"  ></property>
          <property name="lkm_position"  ></property>
          
          <!-- 多对一 -->
          <!-- 
              name属性:引用属性名
              column属性: 外键列名
              class属性: 与我关联的对象完整类名
           -->
            <!-- 
              级联操作:   cascade
                  save-update: 级联保存更新
                  delete:级联删除
                  all:save-update+delete
              级联操作: 简化操作.目的就是为了少些两行代码.
            -->
            <!-- 多的一方: 不能放弃维护关系的.外键字段就在多的一方.  -->
          <many-to-one name="customer" column="lkm_cust_id" class="Customer"  >
          </many-to-one>
      </class>
    
  • 操作关联属性:

    • 基本操作
      //一对多|多对一关系操作
      public class Demo {
      @Test
      //保存客户 以及客户 下的联系人
      public void fun1(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          Customer c = new Customer();
          c.setCust_name("传智播客");
          
          LinkMan lm1 = new LinkMan();
          lm1.setLkm_name("黎活明");
          
          LinkMan lm2 = new LinkMan();
          lm2.setLkm_name("刘悦东");
          
          //表达一对多,客户下有多个联系人
          c.getLinkMens().add(lm1);
          c.getLinkMens().add(lm2);
          
          //表达对对对,联系人属于哪个客户
          lm1.setCustomer(c);
          lm2.setCustomer(c);
          
          
          session.save(c);
      /       session.save(lm1);
      /       session.save(lm2);
          
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
    
      @Test
      //为客户增加联系人
      public void fun2(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          //1> 获得要操作的客户对象
          Customer c = session.get(Customer.class,1l);
          //2> 创建联系人
          LinkMan lm1 = new LinkMan();
          lm1.setLkm_name("郝强勇");
          //3> 将联系人添加到客户,将客户设置到联系人中
          c.getLinkMens().add(lm1);
          lm1.setCustomer(c);
          //4> 执行保存
          session.save(lm1);
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
    
      @Test
      //为客户删除联系人
      public void fun3(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          //1> 获得要操作的客户对象
          Customer c = session.get(Customer.class,1l);
          //2> 获得要移除的联系人
          LinkMan lm = session.get(LinkMan.class, 3l);
          //3> 将联系人从客户集合中移除
          c.getLinkMens().remove(lm);
          lm.setCustomer(null);
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
    }
    
    • 进阶 - 级联

      cascade属性值:save-update,不建议delete

      级联的效果只是简化操作,可以少写几句代码。

    
    //测试级联操作
    public class Demo2 {
      @Test
      //保存客户 以及客户 下的联系人
      //cascade:save-update
      public void fun1(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          Customer c = new Customer();
          c.setCust_name("传智播客");
          
          LinkMan lm1 = new LinkMan();
          lm1.setLkm_name("黎活明");
          
          LinkMan lm2 = new LinkMan();
          lm2.setLkm_name("刘悦东");
          
          //表达一对多,客户下有多个联系人
          c.getLinkMens().add(lm1);
          c.getLinkMens().add(lm2);
          
          //表达对对对,联系人属于哪个客户
          lm1.setCustomer(c);
          lm2.setCustomer(c);
          
          
          session.save(c);
    //        session.save(lm1);
    //        session.save(lm2);
          
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
      
      @Test
      //测试删除客户时,级联删除客户下的联系人
      //cascade:delete
      public void fun2(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          //1> 获得要操作的客户对象
          Customer c = session.get(Customer.class,1l);
          //2>调用delete删除客户
          session.delete(c);
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
      
      @Test
      //保存联系人以及联系人对应的客户
      //cascade:save-update
      public void fun3(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          Customer c = new Customer();
          c.setCust_name("北大青鸟");
          
          LinkMan lm1 = new LinkMan();
          lm1.setLkm_name("刘总");
          
          //表达一对多,客户下有多个联系人
          c.getLinkMens().add(lm1);
          
          //表达对对对,联系人属于哪个客户
          lm1.setCustomer(c);
          
          
          session.save(lm1);
          
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
          
    }
    
    • 进阶 - 关系维护

      优化性能效率:在保存时.两方都会维护外键关系.关系维护两次,冗余了. 多余的维护关系语句,显然是客户这一端在维护关系。

      inverse属性值true时表示当前配置的这一方放弃维护(字面意思反转嘛),默认为false。

    //操作进阶--关系维护属性
    public class Demo3 {
      @Test
      //保存客户 以及客户 下的联系人
      public void fun1(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          Customer c = new Customer();
          c.setCust_name("传智播客");
          
          LinkMan lm1 = new LinkMan();
          lm1.setLkm_name("黎活明");
          
          LinkMan lm2 = new LinkMan();
          lm2.setLkm_name("刘悦东");
          
          //表达一对多,客户下有多个联系人. 
          // 如果客户放弃维护与联系人的关系. 维护关系的代码可以省略
          //c.getLinkMens().add(lm1);
          //c.getLinkMens().add(lm2);
          
          //表达对对对,联系人属于哪个客户
          lm1.setCustomer(c);
          lm2.setCustomer(c);
          
          
          session.save(c);
          session.save(lm1);
          session.save(lm2);
          
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
      
      @Test
      //删除客户
      public void fun2(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          Customer customer = session.get(Customer.class, 1l);
          
          session.delete(customer);
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
          
    }
    

多对多

数据表中

员工表

uid uname
1 张三
2 李四
3 王五

角色表

rid rname
1 清洁工
2 总裁
3 前台

员工角色表(采用中间表设计原则)

uid rid
1 1
1 3
2 2
3 1

实体中:(使用集合来表达互相拥有多个对方)

员工(User)

private Long uid;
private String uname;
private Set<Role> roles;

角色(Role)

private Long rid;
private String rname;
private Set<User> users;

orm元数据中

User.hbm.xml

    <class name="User" table="sys_user" >
        <id name="user_id"  >
            <generator class="native"></generator>
        </id>
        <property name="user_code"  ></property>
        <property name="user_name"  ></property>
        <property name="user_password"  ></property>
        <property name="user_state"  ></property>
    
        <!-- 多对多关系表达 -->
        <!-- 
            name: 集合属性名
            table: 配置中间表名
            key
             |-column:外键,别人引用"我"的外键列名
             class: 我与哪个类是多对多关系
             column:外键.我引用比人的外键列名
         -->
         <!-- cascade级联操作:
                    save-update: 级联保存更新
                    delete:级联删除
                    all:级联保存更新+级联删除
            结论: cascade简化代码书写.该属性使不使用无所谓. 建议要用只用save-update.
                 如果使用delete操作太过危险.尤其在多对多中.不建议使用.
                     -->
        <set name="roles" table="sys_user_role" cascade="save-update" >
            <key column="user_id" ></key>
            <many-to-many class="Role" column="role_id" ></many-to-many>
        </set>
    
    </class>

Role.hbm.xml

    <class name="Role" table="sys_role" >
        <id name="role_id"  >
            <generator class="native"></generator>
        </id>
        <property name="role_name"  ></property>
        <property name="role_memo"  ></property>

    <!-- 使用inverse属性
            true: 放弃维护外键关系
            false(默认值):维护关系
            
        结论: 将来在开发中,如果遇到多对多关系.一定要选择一方放弃维护关系.
             一般谁来放弃要看业务方向. 例如录入员工时,需要为员工指定所属角色.
             那么业务方向就是由员工维护角色. 角色不需要维护与员工关系.角色放弃维护
         -->        
        <set name="users" table="sys_user_role" inverse="true" >
            <key column="role_id" ></key>
            <many-to-many class="User" column="user_id" ></many-to-many>
        </set>
    </class>
  • 操作关联属性

    基本操作

    //多对多关系操作
    public class Demo {
      @Test
      //保存员工以及角色
      public void fun1(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          //1> 创建两个 User
          User u1 = new User();
          u1.setUser_name("郝强勇");
          
          User u2 = new User();
          u2.setUser_name("金家德");
          
          //2> 创建两个 Role
          Role r1 = new Role();
          r1.setRole_name("保洁");
          
          Role r2 = new Role();
          r2.setRole_name("保安");
          //3> 用户表达关系
          u1.getRoles().add(r1);
          u1.getRoles().add(r2);
          
          u2.getRoles().add(r1);
          u2.getRoles().add(r2);
          
          //4> 角色表达关系
          r1.getUsers().add(u1);
          r1.getUsers().add(u2);
          
          r2.getUsers().add(u1);
          r2.getUsers().add(u2);
          
          //5> 调用Save方法一次保存
          session.save(u1);
          session.save(u2);
          session.save(r1);
          session.save(r2);
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
      
      
      @Test
      //为郝强勇新增一个角色
      public void fun3(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          //1> 获得郝强勇用户
          User user = session.get(User.class, 1l);
          //2> 创建公关角色
          Role r = new Role();
          r.setRole_name("男公关");
          //3> 将角色添加到用户中
          user.getRoles().add(r);
          //4> 将角色转换为持久化
          //session.save(r);
          //若在User.hbm.xml中配置了cascade属性为save-update,则可以级联保存,就不必写上面这句代码
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
      
      @Test
      //为郝强勇解除一个角色
      public void fun4(){
          //1 获得session
          Session session = HibernateUtils.openSession();
          //2 开启事务
          Transaction tx = session.beginTransaction();
          //-------------------------------------------------
          //3操作
          //1> 获得郝强勇用户
          User user = session.get(User.class, 1l);
          //2> 获得要操作的角色对象(保洁,保安)
          Role r1 = session.get(Role.class, 1l);
          Role r2 = session.get(Role.class, 2l);
          //3> 将角色从用户的角色集合中移除
          user.getRoles().remove(r1);
          user.getRoles().remove(r2);
          
          //-------------------------------------------------
          //4提交事务
          tx.commit();
          //5关闭资源
          session.close();
      }
    }
    

    进阶 - inverse属性:

    使用inverse属性
              true: 放弃维护外键关系
              false(默认值):维护关系
              
          结论: 将来在开发中,如果遇到多对多关系.一定要选择一方放弃维护关系.
               一般谁来放弃要看业务方向. 例如录入员工时,需要为员工指定所属角色.
               那么业务方向就是由员工维护角色. 角色不需要维护与员工关系.角色放弃维护
    

    进阶 - 级联属性

    cascade级联操作:
                      save-update: 级联保存更新
                      delete:级联删除
                      all:级联保存更新+级联删除
              结论: cascade简化代码书写.该属性使不使用无所谓. 建议要用只用save-update.
                   如果使用delete操作太过危险.尤其在多对多中.不建议使用.
    

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容