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

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

原文地址:https://www.cnblogs.com/Joke-Jay/p/6566727.html