【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
package com.lmb.hibernate.bean;import java.util.ArrayList; import java.util.List;import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; import javax.persistence.OneToMany; import javax.persistence.OrderBy; import javax.persistence.Table;@Entity @Table(name="tb_person") public class Person {@Id@GeneratedValue(strategy=GenerationType.AUTO)private Integer id;private String name;//一對多配置,并配置列關系<span style="color:#ff0000;">@OneToMany(fetch=FetchType.EAGER,targetEntity=Email.class,cascade={CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.MERGE,CascadeType.REFRESH})@JoinColumns(value = { @JoinColumn(name="person id",referencedColumnName="id") })//配置排序方法@OrderBy(value="email desc") </span> private List<Email> emails=new ArrayList<Email>();public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<Email> getEmails() {return emails;}public void setEmails(List<Email> emails) {this.emails = emails;}}
????? 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
package com.lmb.hibernate.bean;import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table;@Entity @Table(name="tb_email") public class Email {@Id@GeneratedValue(strategy=GenerationType.AUTO)private Integer id;private String name;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}??? 配置完畢后要將Person類和Email類在hibernate配置文件中聲明為實體類。實體類要配置在<session-factory? />中。
?
hibernate.cfg.xml
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <!-- Generated by MyEclipse Hibernate Tools. --> <hibernate-configuration><session-factory><property name="dialect">org.hibernate.dialect.MySQLDialect</property><property name="connection.url">jdbc:mysql://localhost:3306/hibernate?characterEncoding=UTF-8</property><property name="connection.username">lmb</property><property name="connection.password">lmb</property><property name="connection.driver_class">com.mysql.jdbc.Driver</property><span style="color:#ff0000;"><mapping class="com.lmb.hibernate.bean.Person" /><mapping class="com.lmb.hibernate.bean.Email" /> </span> </session-factory></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關閉前完成所有的業務邏輯。
總結
以上是生活随笔為你收集整理的【Hibernate】Hibernate实体映射——单边的一对多关系的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Hibernate】Hibernate
- 下一篇: 【Hibernate】Hibernate