轉載於:http://mshijie.javaeye.com/admin/blogs/440057
今天使用JPA(Hibernate)實現一個一對一關聯的時候,發現無法使用延遲加載.Person關聯一個Picture.在讀取Person的時候,顯示的記載了對於的Picture.讀取10個Person發生了11次數據庫查詢.
最後查閱資料後,發現是自己對OneToOne理解不夠透徹所致.之前的關聯是這麼定義的.
- @Entity
- public class Person {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private int id;
- @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "Person
- ")
- private Picture picture;
- }
- @Entity
- public class Picture {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private int id;
- @OneToOne
- private Person Person;
- }
- <span style="font-size: medium;">@Entity
- public class Picture {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private int id;
- @OneToOne
- private Person Person;
- }
- </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.
原因找到了.做了如下修改
- @Entity
- public class Person {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private int id;
- @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
- private Picture picture;
- }
- @Entity
- public class Picture {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private int id;
- @OneToOne(mappedBy = "picture)
- private Person Person;
- }
- <span style="font-size: medium;">@Entity
- public class Picture {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private int id;
- @OneToOne(mappedBy = "picture)
- private Person Person;
- }
- </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,如:
- @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "personnel")
- private List<Reward> rewards = new ArrayList<Reward>();
- <span style="font-size: medium;">@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "personnel")
- 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一致.