hibernate 雙向 OneToOne fetchType lazy 問題

轉載於:http://mshijie.javaeye.com/admin/blogs/440057

今天使用JPA(Hibernate)實現一個一對一關聯的時候,發現無法使用延遲加載.Person關聯一個Picture.在讀取Person的時候,顯示的記載了對於的Picture.讀取10個Person發生了11次數據庫查詢.

最後查閱資料後,發現是自己對OneToOne理解不夠透徹所致.之前的關聯是這麼定義的.

Person 代碼
  1. @Entity  
  2. public class Person {  
  3.   
  4.     @Id  
  5.     @GeneratedValue(strategy = GenerationType.IDENTITY)  
  6.     private int id;  
  7.   
  8.     @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "Person  
  9. ")  
  10.     private Picture picture;  
 
Java代碼
  1. @Entity  
  2. public class Picture {  
  3.     @Id  
  4.     @GeneratedValue(strategy = GenerationType.IDENTITY)  
  5.     private int id;  
  6.   
  7.     @OneToOne  
  8.     private Person Person;  
  9.   
  1. <span style="font-size: medium;">@Entity 
  2. public class Picture { 
  3.     @Id 
  4.     @GeneratedValue(strategy = GenerationType.IDENTITY) 
  5.     private int id; 
  6.  
  7.     @OneToOne 
  8.     private Person Person; 
  9.  
  10. </span> 
@Entity
public class Picture {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@OneToOne
	private Person Person;

}

主表是Picture,從表是Person.外鍵字段定義在Picture表中.在這種情況下.讀取Person會現實的讀取Picture.

因爲如果延遲加載要起作用,就必須設置一個代理對象.但是Personn可以不關聯一個Picture,如果有Picture關聯就設置爲代理對象延遲加載,如果不存在Picture就設置null,因爲外鍵字段是定義在Picture表中的,Hibernate在不讀取Picture表的情況是無法判斷是否關聯有Picture,因此無法判斷設置null還是代理對象,統一設置爲代理對象,也無法滿足不關聯的情況,所以無法使用延遲加載,只有顯示讀取Picture.

原因找到了.做了如下修改

Person 代碼
  1. @Entity  
  2. public class Person {  
  3.   
  4.     @Id  
  5.     @GeneratedValue(strategy = GenerationType.IDENTITY)  
  6.     private int id;  
  7.   
  8.     @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)  
  9.     private Picture picture;  
 
Java代碼
  1. @Entity  
  2. public class Picture {  
  3.     @Id  
  4.     @GeneratedValue(strategy = GenerationType.IDENTITY)  
  5.     private int id;  
  6.   
  7.     @OneToOne(mappedBy = "picture)  
  8.     private Person Person;  
  9.   
  1. <span style="font-size: medium;">@Entity 
  2. public class Picture { 
  3.     @Id 
  4.     @GeneratedValue(strategy = GenerationType.IDENTITY) 
  5.     private int id; 
  6.  
  7.     @OneToOne(mappedBy = "picture) 
  8.     private Person Person; 
  9.  
  10. </span> 
@Entity
public class Picture {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@OneToOne(mappedBy = "picture)
	private Person Person;

}

修改了表的主從關係,這時外鍵字段定義在Personnel表中.Hibernate就可以在不讀取Picture表的情況下根據外鍵字段設置null或者代理對象,延遲加載也就起作用了.

同樣的道理,我們平時在使用一對多的情況是,多端是主表,因此可以通過外鍵字段判斷進而設置代理對象或者null.而在一端,雖然 Hibernate無法判斷是否關聯有對象.但是即使不關聯對象時也不應該設置爲null,而應該設置爲一個空的List或者Map,那麼 Hibernate就可以通過代理這個List或者Map實現延遲加載.這也是爲什麼,我們在設置一端關聯時,一般顯式的new一個ArrayList或者HaskMap,如:

Java代碼
  1. @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "personnel")  
  2. private List<Reward> rewards = new ArrayList<Reward>(); 
  1. <span style="font-size: medium;">@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "personnel"
  2. private List<Reward> rewards = new ArrayList<Reward>();</span> 
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "personnel")
private List<Reward> rewards = new ArrayList<Reward>();

這就是爲了避免使用null表示沒有關聯,和使用空的List一致.


原文出處 http://mshijie.javaeye.com/admin/blogs/440057
發佈了17 篇原創文章 · 獲贊 8 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章