Hibernate实体映射——单边的一对多关系

本文介绍Hibernate中单边一对多关系的配置方法,包括实体类定义、表结构设计及配置文件设置,同时探讨了延迟加载与即时加载的区别。

数据库中的表是有关系的,两个表之间可以通过外键关联。如果把表抽象为实体类,这些关系可以抽象为实体之间的一对一,一对多,多对一等关系。hibernate能处理这些复杂的关系,前提是要正确配置这些关系。

单边的一对多关系

     单边的一对多关系是指一方有集合属性,包含多个多方,而多方没有一方的引用。比较典型的是用户与电子邮件。其中,用户为一方,电子邮件为多方,一个用户可以拥有多个电子邮件记录。

Person.java中有id、name、List<Email>;

Email.java中有id、email;

一个person有多个email,而email中没有person;

对应的表中

tb_person:id、name;

tb_email:id、email、person_id;

若person中有email外键,则一个person的email外键要有多个id,不现实;而email中有person外键,一个email只需要有一个person的外键即可

总结:

一个person有多个email,则person类中有多个email,而person表中没有email外键,email表中有person外键;

 

具体实现如下:

 

Person.java

[html]  view plain  copy
  1. package com.lmb.hibernate.bean;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import javax.persistence.CascadeType;  
  7. import javax.persistence.Entity;  
  8. import javax.persistence.FetchType;  
  9. import javax.persistence.GeneratedValue;  
  10. import javax.persistence.GenerationType;  
  11. import javax.persistence.Id;  
  12. import javax.persistence.JoinColumn;  
  13. import javax.persistence.JoinColumns;  
  14. import javax.persistence.OneToMany;  
  15. import javax.persistence.OrderBy;  
  16. import javax.persistence.Table;  
  17.   
  18. @Entity  
  19. @Table(name="tb_person")  
  20. public class Person {  
  21.   
  22.     @Id  
  23.     @GeneratedValue(strategy=GenerationType.AUTO)  
  24.     private Integer id;  
  25.       
  26.     private String name;  
  27.     //一对多配置,并配置列关系  
  28.     <span style="color:#ff0000;">@OneToMany(fetch=FetchType.EAGER,  
  29.             targetEntity=Email.class,  
  30.             cascade={CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.MERGE,CascadeType.REFRESH}  
  31.             )  
  32.       
  33.     @JoinColumns(value = { @JoinColumn(name="person id",referencedColumnName="id") })  
  34.     //配置排序方法  
  35.     @OrderBy(value="email desc")  
  36. </span>   private List<Email> emails=new ArrayList<Email>();  
  37.   
  38.     public Integer getId() {  
  39.         return id;  
  40.     }  
  41.   
  42.     public void setId(Integer id) {  
  43.         this.id = id;  
  44.     }  
  45.   
  46.     public String getName() {  
  47.         return name;  
  48.     }  
  49.   
  50.     public void setName(String name) {  
  51.         this.name = name;  
  52.     }  
  53.   
  54.     public List<Email> getEmails() {  
  55.         return emails;  
  56.     }  
  57.   
  58.     public void setEmails(List<Email> emails) {  
  59.         this.emails = emails;  
  60.     }  
  61.       
  62.       
  63. }  


      Person实体中使用@OneToMany配置一对多关系。fetch配置加载方式(延迟加载fetch=FetchType.LAZY、即时加载fetch=FetchType.EAGER);targetEntity配置集合属性中的类型,由于emails属性类型为List<Email>,用反省制定了集合内为Email对象,因此targetEntity可省略;cascade配置级联方式,本例配置为PERSIST、REMOVE、MERGE、REFRESH,表示在保存、删除、修改、刷新Person类时会自动在数据库中保存、删除、修改、刷新属于它的Email对象。配置级联关系后,可以通过操作Person类来操作Email类。该配置也等同于CascadeType.ALL。@OrderBy配置排序方式,本例将Email按照email列降序排列。

    Email实体类比较简单,由于是单边关系映射,Email中没有用户实体的引用,只是一个简单的POJO。

 

Email.java

[html]  view plain  copy
  1. package com.lmb.hibernate.bean;  
  2.   
  3. import javax.persistence.Entity;  
  4. import javax.persistence.GeneratedValue;  
  5. import javax.persistence.GenerationType;  
  6. import javax.persistence.Id;  
  7. import javax.persistence.Table;  
  8.   
  9. @Entity  
  10. @Table(name="tb_email")  
  11. public class Email {  
  12.   
  13.     @Id  
  14.     @GeneratedValue(strategy=GenerationType.AUTO)  
  15.     private Integer id;  
  16.       
  17.     private String name;  
  18.   
  19.     public Integer getId() {  
  20.         return id;  
  21.     }  
  22.   
  23.     public void setId(Integer id) {  
  24.         this.id = id;  
  25.     }  
  26.   
  27.     public String getName() {  
  28.         return name;  
  29.     }  
  30.   
  31.     public void setName(String name) {  
  32.         this.name = name;  
  33.     }  
  34.       
  35.       
  36. }  


    配置完毕后要将Person类和Email类在hibernate配置文件中声明为实体类。实体类要配置在<session-factory  />中。

 

hibernate.cfg.xml

[html]  view plain  copy
  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. <!-- Generated by MyEclipse Hibernate Tools.                   -->  
  6. <hibernate-configuration>  
  7.   
  8.     <session-factory>  
  9.         <property name="dialect">org.hibernate.dialect.MySQLDialect</property>  
  10.         <property name="connection.url">jdbc:mysql://localhost:3306/hibernate?characterEncoding=UTF-8</property>  
  11.         <property name="connection.username">lmb</property>  
  12.         <property name="connection.password">lmb</property>  
  13.         <property name="connection.driver_class">com.mysql.jdbc.Driver</property>  
  14.         <span style="color:#ff0000;"><mapping class="com.lmb.hibernate.bean.Person" />  
  15.         <mapping class="com.lmb.hibernate.bean.Email" />  
  16. </span>      
  17.     </session-factory>  
  18.   
  19. </hibernate-configuration>  

 

以上使用@注解实现的,当然我们还可以使用XML配置的方式实现,这了我就不在列出。


延迟加载与即时加载

即时加载(Eagar Fetching),查询Person的时候自动加载相关的Email

延迟加载(Lazy Fetching),只有在需要的时候才查询Email(默认)

延迟加载异常

   一般来说,延时加载比即时加载节省资源。但是如果处理不当,延迟加载容易抛出延时加载异常(LazyInitializationException)。这是因为延迟加载时,只有第一次调用person.getEmail()才会加载emails数据,如果这时候数据库连接已经关闭了,就会因为无法加载数据而抛出异常。

 

解决办法:(两种) 

1、在session关闭前调用一次上面的方法(person.getEmail()),强迫hibernate加载Email数据;session关闭后JDBC连接就关闭了,无法再从数据库读取任何数据了。

2、延迟session的范围,使session关闭前完成所有的业务逻辑。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值