懶加載是指程序推遲訪問數據庫,這樣作能夠保證有時候沒必要要的訪問數據庫,由於訪問一次數據庫是比較耗時的。
html
1、load方法的懶加載java
先看以下代碼段linux
[java] view plaincopyprint?web
<EMBED id=ZeroClipboardMovie_1 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=14 width=29 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=29&height=14" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">數據庫
<span style="font-size:16px;">public class UserManager { session
public static void main(String[] args) { app
Users user = new Users(); dom
user.setBirthday(new Date()); oop
Name name = new Name(); fetch
name.setFirstName("guo");
name.setLastName("zhao");
user.setName(name);
addUser(user);
Users users = getUser(user.getId());
System.out.println(users.getName());
}
static Users getUser(int id){
Session session = HibernateUtil.getSession();
try {
Users users = (Users) session.load(Users.class, id);
return users;
} finally{
session.close();
}
}
static void addUser(Users users){
Session session = null;
Transaction tx = null;
try {
session = HibernateUtil.getSession();
tx = session.beginTransaction();
session.save(users);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) {
tx.rollback();
}
throw e;
}finally{
if(session!=null){
session.close();
}
}
}
}</span>
上面代碼是先增長一個用戶、而後再查詢這個用戶的name組合屬性。運行上面的時候,該程序會拋出這樣一個異常:
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session這就是懶加載不能初始化異常。其緣由就在於no session。在前面個持久化對象中已經說明:使用load方法時,該方法將具備延遲加載的功能,load方法並不會當即去訪問數據庫,它會返回一個代理對象,只有當你真正去訪問這個對象的時候,它纔會去訪問數據庫。
經過上面的圖,咱們看出,hibernate根本就沒有select語句,也就是說hibernate沒有去訪問數據庫,因此這個時候你去訪問它確定是沒有的。但爲何沒有拋出空指針異常?沒有拋出空指針異常,也就是說明User對象是存在的,那它是什麼呢?經過輸出user.getClass()能夠看出是這樣一個東西:
class com.hibernate.domain.Users_$$_javassist_5。
這個user就是load返回的代理對象。可是這個對象並非咱們所要的。咱們所要的是一個User實例對象。
那麼怎麼解決這個問題呢?
第一種方法:在關閉session以前訪問該對象
[java] view plaincopyprint?
<EMBED id=ZeroClipboardMovie_2 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=14 width=29 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=29&height=14" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
<span style="font-size:16px;"> static Users getUser(int id){
Session session = HibernateUtil.getSession();
try {
Users users = (Users) session.load(Users.class, id);
users.getName();
return users;
} finally{
session.close();
}
}</span>
不過這句話看起來會很奇怪。咱們一般會採用以下的方式
[java] view plaincopyprint?
<EMBED id=ZeroClipboardMovie_3 name=ZeroClipboardMovie_3 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=14 width=29 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=3&width=29&height=14" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
<span style="font-size:16px;"> static Users getUser(int id){
Session session = HibernateUtil.getSession();
try {
Users users = (Users) session.load(Users.class, id);
Hibernate.initialize(users);
return users;
} finally{
session.close();
}
}</span>
利用hibernate的initialize()方法將這個代理對象給初始化。
注:在使用代理對象的getId()方法和getClass()方法的時候,並不會拋出不能初始化異常,由於這兩個屬性並不用查詢數據庫。
2、在缺省的狀況下,hibernate對於關聯關係會採用懶加載的方式。也就是說1-一、1-N、N-一、N-N都存在懶加載的問題。
2.一、one-to-one懶加載
一對一的懶加載並不經常使用,由於懶加載的目的是爲了減小與數據庫的交互,從而提升執行效率,而在一對一關係中,主表中的每一條數據只對應從表的一條數據庫,就算都查詢也不會增長多少交互的成本,並且主表不能有contrained=true,因此主表是不能懶加載的。可是從表能夠有。
實現此種懶加載必須在從對象這邊同時知足三個條件:
1、lazy!=false(lazy的屬性有三個選項分別爲:no-proxy、false和proxy)
2、Constrained = true ;
3、fetch=select。
注:當fetch設置爲join時,懶加載就會失效。由於fetch的做用是抓取方式,他有兩個值分別問select和join,默認值爲select。即在設爲join時,他會直接將從表信息以join方式查詢到而不是再次使用select查詢,這樣致使了懶加載的失效。
2.二、one-to-many懶加載
與one-to-one關聯不一樣,對one-to-many而言,主表的每一條屬性都會對應從表的多條數據,這個時候懶加載就顯得很是有效了。好比一個部門裏面有多個員工,若是沒有懶加載,每查詢這個部門的時候都會查詢出多個員工,這會大大增長與數據庫交互的成本。因此Hbernate默認的是加入懶加載的。這就是查詢集合屬性的時候返回的是一個PersistentIndexed*類型對象的緣由。該對象其實就是一個代理對象。固然,能夠在映射文件中經過將lazy屬性設爲假來禁用。
Hibernate默認對one-to-many就是使用的懶加載,但用戶也能夠取消懶加載操做:
一:設置lazy=」false」;
二:設置fetch=」join」.
實現此種懶加載必須在從對象這邊同時知足兩個個條件:
1、lazy!=false(lazy的屬性有三個選項分別爲:no-proxy、false和proxy)
2、fetch=select。
2.三、mang-to-one懶加載
此關聯關係的懶加載和one-to-one的懶加載同樣都是可要可不要的,由於對執行效率的提升都不是很是明顯。雖然多對一與一對一關係方式相同,可是在Hibernate中多對一時,默認是進行懶加載的。另外有一點須要注意的是懶加載並不會區分集合屬性裏面是否有值,即便是沒有值,他依然會使用懶加載。
實現此種懶加載必須在從對象這邊同時知足兩個個條件:
1、lazy!=false(lazy的屬性有三個選項分別爲:no-proxy、false和proxy)
2、fetch=select
2.四、many-to-many懶加載
此關聯關係的懶加載和one-to-many的懶加載同樣對程序的執行效率的提升都是很是明顯的。
實現此種懶加載必須在從對象這邊同時知足兩個個條件:
1、lazy!=false(lazy的屬性有三個選項分別爲:no-proxy、false和proxy)
2、fetch=select
可以懶加載的對象都是被改過的代理對象,當相應的對象沒有關閉時,訪問這些懶加載對象的屬性(getId和getClass除外)hibernate會初始化這些代理,或用hibernate.initalize(proxy)來初始化代理對象;當關閉session後在訪問懶加載的對象就會出現異常