zoukankan      html  css  js  c++  java
  • Hibernate 一对多

    表与表之间关系回顾(重点)

    1 一对多

    (1)分类和商品关系,一个分类里面有多个商品,一个商品只能属于一个分类

    (2)客户和联系人是一对多关系

    - 客户:与公司有业务往来,百度、新浪、360

    - 联系人:公司里面的员工,百度里面有很多员工,联系员工

    ** 公司和公司员工的关系

    - 客户是一,联系人是多

    - 一个客户里面有多个联系人,一个联系人只能属于一个客户

    (3)一对多建表:通过外键建立关系

    2 多对多
    (1)订单和商品关系,一个订单里面有多个商品,一个商品属于多个订单

    (2)用户和角色多对多关系
    - 用户: 小王、小马、小宋
    - 角色:总经理、秘书、司机、保安
    ** 比如小王 可以 是总经理,可以是司机
    ** 比如小宋 可以是司机,可以是秘书,可以保安
    ** 比如小马 可以是 秘书,可以是总经理
    - 一个用户里面可以有多个角色,一个角色里面可以有多个用户

    (3)多对多建表:创建第三张表维护关系

    3 一对一

    (1)在中国,一个男人只能有一个妻子,一个女人只能有一个丈夫

    Hibernate的一对多操作(重点)

    一对多映射配置(重点)

    以客户和联系人为例:客户是一,联系人是多

    第一步 创建两个实体类,客户和联系人

    第二步 让两个实体类之间互相表示

    (1)在客户实体类里面表示多个联系人

    - 一个客户里面有多个联系人

    (2)在联系人实体类里面表示所属客户
    - 一个联系人只能属于一个客户

    第三步 配置映射关系

    (1)一般一个实体类对应一个映射文件

    (2)把映射最基本配置完成

    (3)在映射文件中,配置一对多关系

    - 在客户映射文件中,表示所有联系人

     

    - 在联系人映射文件中,表示所属客户

    第四步 创建核心配置文件,把映射文件引入到核心配置文件中

    代码实践:

     1 package org.model;
     2 
     3 import java.util.HashSet;
     4 import java.util.Set;
     5 
     6 public class Customer {
     7     private Integer cid;
     8     private String cname;
     9     private String tel;
    10     //在一方创建多的集合 并且生成set get 方法
    11     private Set<LinkMan> setlinkman=new HashSet<LinkMan>();
    12 
    13     public Set<LinkMan> getSetlinkman() {
    14         return setlinkman;
    15     }
    16     public void setSetlinkman(Set<LinkMan> setlinkman) {
    17         this.setlinkman = setlinkman;
    18     }
    19     public Integer getCid() {
    20         return cid;
    21     }
    22     public void setCid(Integer cid) {
    23         this.cid = cid;
    24     }
    25     public String getCname() {
    26         return cname;
    27     }
    28     public void setCname(String cname) {
    29         this.cname = cname;
    30     }
    31     public String getTel() {
    32         return tel;
    33     }
    34     public void setTel(String tel) {
    35         this.tel = tel;
    36     }
    37 }
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC 
     3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5     <hibernate-mapping>
     6         <class name="org.model.Customer" table="t_customer">
     7             <id name="cid" column="cid">
     8                 <generator class="native"></generator>
     9             </id>
    10             <property name="cname" column="cname"></property>
    11             <property name="tel" column="tel"></property>
    12             
    13             <set name="setlinkman">
    14                 <!-- key中column的属性值为外键的名字 可随便写  作用指定外键 在多的一方添加外键 所以 根据class中的路径  在多方 创建的表中就会有clid字段 作为外键 -->
    15                 <key column="clid"></key>
    16                 <!-- class属性中写的是关联表实体类的名称 -->
    17                 <one-to-many class="org.model.LinkMan"/>
    18             </set>    
    19         </class>
    20     </hibernate-mapping>
     1 package org.model;
     2 
     3 public class LinkMan {
     4     private Integer lid;
     5     private String lname;
     6     private String tel;
     7     //在多的一方 指定所属的客户  当然也可以只写一个字段(关联外键的id)  这里写的是一个对象
     8     private Customer customer;
     9     
    10     public Customer getCustomer() {
    11         return customer;
    12     }
    13     public void setCustomer(Customer customer) {
    14         this.customer = customer;
    15     }
    16     public Integer getLid() {
    17         return lid;
    18     }
    19     public void setLid(Integer lid) {
    20         this.lid = lid;
    21     }
    22     public String getLname() {
    23         return lname;
    24     }
    25     public void setLname(String lname) {
    26         this.lname = lname;
    27     }
    28     public String getTel() {
    29         return tel;
    30     }
    31     public void setTel(String tel) {
    32         this.tel = tel;
    33     }
    34 }
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC 
     3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5     <hibernate-mapping>
     6         <class name="org.model.LinkMan" table="t_linkman">
     7             <id name="lid" column="lid">
     8                 <generator class="native"></generator>
     9             </id>
    10             <property name="lname" column="lname"></property>
    11             <property name="tel" column="tel"></property>
    12             <!-- name中写的是linkman表中关联对象的名称 column写的是外间的名称 class写的是关联对象的类的全路径 指定被关联的实体类-->
    13             <many-to-one name="customer" column="clid" class="org.model.Customer"></many-to-one>
    14         </class>
    15     </hibernate-mapping>

    核心配置文件

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE hibernate-configuration PUBLIC
     3     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
     4     "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
     5 <hibernate-configuration>
     6     <session-factory>
     7         <!-- 第一步:配置数据库信息 -->
     8         <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
     9         <property name="hibernate.connection.username">root</property>
    10         <property name="hibernate.connection.password">jay571018</property>
    11         <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate3_demo1</property>
    12         <!-- 第二步:配置Hibernate信息 -->
    13         <property name="hibernate.show_sql">true</property>
    14         <property name="hibernate.format_sql">true</property>
    15         <!-- 自动建表 -->
    16         <property name="hibernate.hbm2ddl.auto">update</property>
    17         <!-- 设置数据库方言 -->
    18         <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    19         <!-- 设置与本地线程绑定session -->
    20         <property name="hibernate.current_session_context_class">thread</property>
    21         
    22         <!-- 第三步:引入对象关系映射文件 -->
    23         <mapping resource="org/model/Customer.hbm.xml"/>
    24         <mapping resource="org/model/LinkMan.hbm.xml"/>
    25     </session-factory>
    26 </hibernate-configuration>

    sessionfactory

     1 package org.util;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.cfg.Configuration;
     6 
     7 public class SessionFactoryUtils {
     8      static Configuration configuration=null;
     9      static SessionFactory sf=null;
    10     
    11     static{
    12         configuration=new Configuration();
    13         configuration.configure();//加载核心配置文件
    14         sf=configuration.buildSessionFactory();
    15     }
    16     public static SessionFactory getsessionfactory(){
    17         return sf;
    18     }
    19     
    20     public static Session get(){
    21         return sf.getCurrentSession();
    22     }
    23     
    24     public static void main(String[] args){
    25         
    26     }
    27     
    28 }

    执行之后效果:

    自动完成建表  并且在联系人表(多方)中添加了外键

    一对多级联操作

    级联操作

    1 级联保存

    (1)添加一个客户,为这个客户添加多个联系人

    2 级联删除

    (1)删除某一个客户,这个客户里面的所有的联系人也删除

    一对多级联保存

    1 添加客户,为这个客户添加一个联系人

    (1)复杂写法:

     1 //演示一对多级联保存
     2     @Test
     3     public void testAddDemo1() {
     4         SessionFactory sessionFactory = null;
     5         Session session = null;
     6         Transaction tx = null;
     7         try {
     8             //得到sessionFactory
     9             sessionFactory = HibernateUtils.getSessionFactory();
    10             //得到session
    11             session = sessionFactory.openSession();
    12             //开启事务
    13             tx = session.beginTransaction();
    14             
    15             // 添加一个客户,为这个客户添加一个联系人
    16             //1 创建客户和联系人对象
    17             Customer customer = new Customer();
    18             customer.setCustName("传智播客");
    19             customer.setCustLevel("vip");
    20             customer.setCustSource("网络");
    21             customer.setCustPhone("110");
    22             customer.setCustMobile("999");
    23             
    24             LinkMan linkman = new LinkMan();
    25             linkman.setLkm_name("lucy");
    26             linkman.setLkm_gender("男");
    27             linkman.setLkm_phone("911");
    28             
    29             //2 在客户表示所有联系人,在联系人表示客户        
    30             // 建立客户对象和联系人对象关系
    31             //2.1 把联系人对象 放到客户对象的set集合里面
    32             customer.getSetLinkMan().add(linkman);
    33             //2.2 把客户对象放到联系人里面
    34             linkman.setCustomer(customer);
    35             
    36             //3 保存到数据库
    37             session.save(customer);
    38             session.save(linkman);
    39             
    40             //提交事务
    41             tx.commit();
    42 
    43         }catch(Exception e) {
    44             tx.rollback();
    45         }finally {
    46             session.close();
    47             //sessionFactory不需要关闭
    48             sessionFactory.close();
    49         }
    50     }

    执行效果:

    (2)简化写法

    - 一般根据客户添加联系人

    第一步 在客户映射文件中进行配置

    - 在客户映射文件里面set标签进行配置

    第二步 创建客户和联系人对象,只需要把联系人放到客户里面就可以了,最终只需要保存客户就可以了

     1 //演示一对多级联保存
     2     @Test
     3     public void testAddDemo2() {
     4         SessionFactory sessionFactory = null;
     5         Session session = null;
     6         Transaction tx = null;
     7         try {
     8             //得到sessionFactory
     9             sessionFactory = HibernateUtils.getSessionFactory();
    10             //得到session
    11             session = sessionFactory.openSession();
    12             //开启事务
    13             tx = session.beginTransaction();
    14             // 添加一个客户,为这个客户添加一个联系人
    15             //1 创建客户和联系人对象
    16             Customer customer = new Customer();
    17             customer.setCustName("百度");
    18             customer.setCustLevel("普通客户");
    19             customer.setCustSource("网络");
    20             customer.setCustPhone("110");
    21             customer.setCustMobile("999");
    22         
    23             LinkMan linkman = new LinkMan();
    24             linkman.setLkm_name("小宏");
    25             linkman.setLkm_gender("男");
    26             linkman.setLkm_phone("911");
    27             //2 把联系人放到客户里面
    28             customer.getSetLinkMan().add(linkman);
    29             //3 保存客户
    30             session.save(customer);
    31             
    32             //提交事务
    33             tx.commit();
    34         }catch(Exception e) {
    35             tx.rollback();
    36         }finally {
    37             session.close();
    38             //sessionFactory不需要关闭
    39             sessionFactory.close();
    40         }
    41     }

    代码实践:

    修改customer配置文件

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC 
     3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5     <hibernate-mapping>
     6         <class name="org.model.Customer" table="t_customer">
     7             <id name="cid" column="cid">
     8                 <generator class="native"></generator>
     9             </id>
    10             <property name="cname" column="cname"></property>
    11             <property name="tel" column="tel"></property>
    12             
    13             <set name="setlinkman" cascade="save-update">
    14                 <!-- key中column的属性值为外键的名字 可随便写  作用指定外键 在多的一方添加外键 所以 根据class中的路径  在多方 创建的表中就会有clid字段 作为外键 -->
    15                 <key column="clid"></key>
    16                 <!-- class属性中写的是关联表实体类的名称 -->
    17                 <one-to-many class="org.model.LinkMan"/>
    18             </set>    
    19         </class>
    20     </hibernate-mapping>
     1 package org.testdemo;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.Transaction;
     6 import org.junit.Test;
     7 import org.model.Customer;
     8 import org.model.LinkMan;
     9 import org.util.SessionFactoryUtils;
    10 
    11 public class OnetoMany {
    12     @Test
    13     public void test1(){
    14         //复杂写法  没有配置cascade属性
    15         Session session=null;
    16         Transaction tran=null;
    17         try{
    18             session=SessionFactoryUtils.get();
    19             //开启事务
    20             tran=session.beginTransaction();
    21             
    22             Customer c=new Customer();
    23             c.setCname("阿里");
    24             c.setTel("0379-1534350");
    25             
    26             LinkMan l=new LinkMan();
    27             l.setLname("马云");
    28             l.setTel("15035286558");
    29             
    30             //分别建立联系
    31             c.getSetlinkman().add(l);
    32             l.setCustomer(c);
    33             //然后分别保存
    34             session.save(c);
    35             session.save(l);
    36             
    37             //提交事务
    38             tran.commit();
    39             
    40         }catch(Exception e){
    41             e.printStackTrace();
    42         }finally{
    43         }
    44         
    45     }
    46     @Test
    47     public void test2(){
    48         //简单写法  在客户映射文件中配置cascade属性  因为联系人表的外键 约束与客户表的主键 所以一般都是先保存客户表 所以在客户表中进行配置
    49         Session session=null;
    50         Transaction tran=null;
    51         try{
    52             session=SessionFactoryUtils.get();
    53             //开启事务
    54             tran=session.beginTransaction();
    55             
    56             Customer c=new Customer();
    57             c.setCname("百度");
    58             c.setTel("0379-1534350");
    59             
    60             LinkMan l=new LinkMan();
    61             l.setLname("李彦宏");
    62             l.setTel("15035286558");
    63             
    64             //不需要分别建立联系
    65 //            c.getSetlinkman().add(l);
    66 //            l.setCustomer(c);
    67             //因为客户表是主控方 只需要在客户对象中关联 联系人表的对象即可  
    68             //然后分别保存
    69 //            session.save(c);
    70 //            session.save(l);
    71             c.getSetlinkman().add(l);
    72             session.save(c);
    73             
    74             //提交事务
    75             tran.commit();
    76             
    77         }catch(Exception e){
    78             e.printStackTrace();
    79         }finally{
    80         }
    81         
    82     }
    83 }

    执行效果:

    一对多级联删除

    1 删除某个客户,把客户里面所有的联系人删除

    2 具体实现 

    第一步 在客户(主控方)映射文件set标签,进行配置

    (1)使用属性cascade属性值 delete

    第二步 在代码中直接删除客户

    (1)根据id查询对象,调用session里面delete方法删除

     

    3 执行过程:

    (1)根据id查询客户

     

    (2)根据外键id值查询联系人

     

    (3)把联系人外键设置为null

     

    (4)删除联系人和客户

    代码实践:

     1 @Test
     2     public void test3(){
     3         //进行级联删除操作  需要在主控方set标签中增加属性配置
     4         Session session=null;
     5         Transaction tran=null;
     6         try{
     7             session=SessionFactoryUtils.get();
     8             //开启事务
     9             tran=session.beginTransaction();
    10             //A级联删除删除的是主控方的对象  从而把依赖的对象也删除  联系人表的外键依赖于客户表中的主键
    11             Customer c=session.get(Customer.class,4);
    12             session.delete(c);
    13             //B下面这种方式不会级联删除  执行之后只会删掉联系人表中对应的记录  而客户表不会删
    14 //            LinkMan l=session.get(LinkMan.class,5);//
    15 //            session.delete(l);
    16              tran.commit();
    17             
    18         }catch(Exception e){
    19             e.printStackTrace();
    20         }finally{
    21         }    
    22     }

    删除之前:

    A代码  级联删除之后:

    执行控制台打印  删除过程

    Hibernate: 
        select
            customer0_.cid as cid1_0_0_,
            customer0_.cname as cname2_0_0_,
            customer0_.tel as tel3_0_0_ 
        from
            t_customer customer0_ 
        where
            customer0_.cid=?
    Hibernate: 
        select
            setlinkman0_.clid as clid4_1_0_,
            setlinkman0_.lid as lid1_1_0_,
            setlinkman0_.lid as lid1_1_1_,
            setlinkman0_.lname as lname2_1_1_,
            setlinkman0_.tel as tel3_1_1_,
            setlinkman0_.clid as clid4_1_1_ 
        from
            t_linkman setlinkman0_ 
        where
            setlinkman0_.clid=?
    Hibernate: 
        update
            t_linkman 
        set
            clid=null 
        where
            clid=?
    Hibernate: 
        delete 
        from
            t_linkman 
        where
            lid=?
    Hibernate: 
        delete 
        from
            t_customer 
        where
            cid=?

    B代码  删除之后:

    删除过程:

    Hibernate: 
        select
            linkman0_.lid as lid1_1_0_,
            linkman0_.lname as lname2_1_0_,
            linkman0_.tel as tel3_1_0_,
            linkman0_.clid as clid4_1_0_ 
        from
            t_linkman linkman0_ 
        where
            linkman0_.lid=?
    Hibernate: 
        delete 
        from
            t_linkman 
        where
            lid=?
    

     

    一对多修改操作(inverse属性)

    1 让lucy联系人所属客户不是传智播客,而是百度

    2 inverse属性

    (1)因为hibernate双向维护外键,在客户和联系人里面都需要维护外键,修改客户时候修改一次外键,修改联系人时候也修改一次外键,造成效率问题

     

    (2)解决方式:让其中的一方不维护外键
    - 一对多里面,让其中一方放弃外键维护
    - 一个国家有总统,国家有很多人,总统不能认识国家所有人,国家所有人可以认识总统

    (3)具体实现:
    在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性

     

    代码实现:

    操作之前:

    操作之后:

    测试代码:

    	@Test
    	public void test4(){
    		Session session=null;
    		Transaction tran=null;
    		try{
    			session=SessionFactoryUtils.get();
    			//开启事务
    			tran=session.beginTransaction();
    			Customer al=session.get(Customer.class,2);
    			LinkMan linkman=session.get(LinkMan.class,111);
    			al.getSetlinkman().add(linkman);
    			linkman.setCustomer(al);//因为是持久态对象 所以不需要进行save保存 当事务提交的时候 会自动进行保存
    			
    			
    			tran.commit();
    			
    		}catch(Exception e){
    			e.printStackTrace();
    		}finally{
    		}	
    	}
    

      

    没有添加inverse属性执行过程:

    Hibernate: 
        select
            customer0_.cid as cid1_0_0_,
            customer0_.cname as cname2_0_0_,
            customer0_.tel as tel3_0_0_ 
        from
            t_customer customer0_ 
        where
            customer0_.cid=?
    Hibernate: 
        select
            linkman0_.lid as lid1_1_0_,
            linkman0_.lname as lname2_1_0_,
            linkman0_.tel as tel3_1_0_,
            linkman0_.clid as clid4_1_0_ 
        from
            t_linkman linkman0_ 
        where
            linkman0_.lid=?
    Hibernate: 
        select
            setlinkman0_.clid as clid4_1_0_,
            setlinkman0_.lid as lid1_1_0_,
            setlinkman0_.lid as lid1_1_1_,
            setlinkman0_.lname as lname2_1_1_,
            setlinkman0_.tel as tel3_1_1_,
            setlinkman0_.clid as clid4_1_1_ 
        from
            t_linkman setlinkman0_ 
        where
            setlinkman0_.clid=?
    Hibernate: 
        update
            t_linkman 
        set
            lname=?,
            tel=?,
            clid=? 
        where
            lid=?
    Hibernate: 
        update
            t_linkman 
        set
            clid=? 
        where
            lid=?
    

      多了一次更新

    现在在一方set表签中添加inverse属性  让它放弃表的维护工作  

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC 
     3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5     <hibernate-mapping>
     6         <class name="org.model.Customer" table="t_customer">
     7             <id name="cid" column="cid">
     8                 <generator class="native"></generator>
     9             </id>
    10             <property name="cname" column="cname"></property>
    11             <property name="tel" column="tel"></property>
    12             <!-- 默认值是false 不放弃维护  这里设置为false 表示放弃维护 -->
    13             <set name="setlinkman" cascade="save-update,delete" inverse="true">
    14                 <!-- key中column的属性值为外键的名字 可随便写  作用指定外键 在多的一方添加外键 所以 根据class中的路径  在多方 创建的表中就会有clid字段 作为外键 -->
    15                 <key column="clid"></key>
    16                 <!-- class属性中写的是关联表实体类的名称 -->
    17                 <one-to-many class="org.model.LinkMan"/>
    18             </set>    
    19         </class>
    20     </hibernate-mapping>

    执行代码观察控制台:

    Hibernate: 
        select
            customer0_.cid as cid1_0_0_,
            customer0_.cname as cname2_0_0_,
            customer0_.tel as tel3_0_0_ 
        from
            t_customer customer0_ 
        where
            customer0_.cid=?
    Hibernate: 
        select
            linkman0_.lid as lid1_1_0_,
            linkman0_.lname as lname2_1_0_,
            linkman0_.tel as tel3_1_0_,
            linkman0_.clid as clid4_1_0_ 
        from
            t_linkman linkman0_ 
        where
            linkman0_.lid=?
    Hibernate: 
        select
            setlinkman0_.clid as clid4_1_0_,
            setlinkman0_.lid as lid1_1_0_,
            setlinkman0_.lid as lid1_1_1_,
            setlinkman0_.lname as lname2_1_1_,
            setlinkman0_.tel as tel3_1_1_,
            setlinkman0_.clid as clid4_1_1_ 
        from
            t_linkman setlinkman0_ 
        where
            setlinkman0_.clid=?
    Hibernate: 
        update
            t_linkman 
        set
            lname=?,
            tel=?,
            clid=? 
        where
            lid=?
    

     少了一次更新的语句,性能提高

  • 相关阅读:
    Java volatile 关键字底层实现原理解析
    volatile关键字?MESI协议?指令重排?内存屏障?这都是啥玩意
    聊聊缓存一致性协议
    JIT原理
    java 泛型详解
    Java中的逆变与协变
    疯狂的String
    java中synchronized与Lock的异同
    不使用的大对象为什么要手动设置null,真的有效吗?
    不使用反射如何调用某个实例对象的方法
  • 原文地址:https://www.cnblogs.com/Joke-Jay/p/6566727.html
Copyright © 2011-2022 走看看