日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

hibernate 延迟加载问题探讨

發布時間:2025/5/22 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hibernate 延迟加载问题探讨 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
延遲初始化錯誤是運用Hibernate開發項目時最常見的錯誤。如果對一個類或者集合配置了延遲檢索策略,那么必須當代理類實例或代理集合處于持久化狀態(即處于Session范圍內)時,才能初始化它。如果在游離狀態時才初始化它,就會產生延遲初始化錯誤。

下面把Customer.hbm.xml文件的<class>元素的lazy屬性設為true,表示使用延遲檢索策略:

<class name="mypack.Customer" table="CUSTOMERS" lazy="true">

當執行Session的load()方法時,Hibernate不會立即執行查詢CUSTOMERS表的select語句,僅僅返回Customer類的代理類的實例,這個代理類具由以下特征:

(1) 由Hibernate在運行時動態生成,它擴展了Customer類,因此它繼承了Customer類的所有屬性和方法,但它的實現對于應用程序是透明的。
(2) 當Hibernate創建Customer代理類實例時,僅僅初始化了它的OID屬性,其他屬性都為null,因此這個代理類實例占用的內存很少。
(3)當應用程序第一次訪問Customer代理類實例時(例如調用customer.getXXX()或customer.setXXX()方法), Hibernate會初始化代理類實例,在初始化過程中執行select語句,真正從數據庫中加載Customer對象的所有數據。但有個例外,那就是當應用程序訪問Customer代理類實例的getId()方法時,Hibernate不會初始化代理類實例,因為在創建代理類實例時OID就存在了,不必到數據庫中去查詢。

提示:Hibernate采用CGLIB工具來生成持久化類的代理類。CGLIB是一個功能強大的Java字節碼生成工具,它能夠在程序運行時動態生成擴展 Java類或者實現Java接口的代理類。關于CGLIB的更多知識,請參考:[url]http://cglib.sourceforge.net/[/url]

以下代碼先通過Session的load()方法加載Customer對象,然后訪問它的name屬性:

tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,new Long(1));
customer.getName();
tx.commit();

在運行session.load()方法時Hibernate不執行任何select語句,僅僅返回Customer類的代理類的實例,它的OID為1,這是由load()方法的第二個參數指定的。當應用程序調用customer.getName()方法時,Hibernate會初始化Customer代理類實例,從數據庫中加載Customer對象的數據,執行以下select語句:

select * from CUSTOMERS where ID=1;
select * from ORDERS where CUSTOMER_ID=1;

當<class>元素的lazy屬性為true,會影響Session的load()方法的各種運行時行為,下面舉例說明。

1.如果加載的Customer對象在數據庫中不存在,Session的load()方法不會拋出異常,只有當運行customer.getName()方法時才會拋出以下異常:

ERROR LazyInitializer:63 - Exception initializing proxy
net.sf.hibernate.ObjectNotFoundException: No row with the given identifier exists: 1, of class:
mypack.Customer

2.如果在整個Session范圍內,應用程序沒有訪問過Customer對象,那么Customer代理類的實例一直不會被初始化,Hibernate不會執行任何select語句。以下代碼試圖在關閉Session后訪問Customer游離對象:

tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,new Long(1));
tx.commit();
session.close();
customer.getName();

由于引用變量customer引用的Customer代理類的實例在Session范圍內始終沒有被初始化,因此在執行customer.getName()方法時,Hibernate會拋出以下異常:

ERROR LazyInitializer:63 - Exception initializing proxy
net.sf.hibernate.HibernateException: Could not initialize proxy - the owning Session was closed

由此可見,Customer代理類的實例只有在當前Session范圍內才能被初始化。

3.net.sf.hibernate.Hibernate類的initialize()靜態方法用于在Session范圍內顯式初始化代理類實例,isInitialized()方法用于判斷代理類實例是否已經被初始化。例如:

tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,new Long(1));
if(!Hibernate.isInitialized(customer))
Hibernate.initialize(customer);
tx.commit();
session.close();
customer.getName();

以上代碼在Session范圍內通過Hibernate類的initialize()方法顯式初始化了Customer代理類實例,因此當Session關閉后,可以正常訪問Customer游離對象。

4.當應用程序訪問代理類實例的getId()方法時,不會觸發Hibernate初始化代理類實例的行為,例如:

tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,new Long(1));
customer.getId();
tx.commit();
session.close();
customer.getName();

當應用程序訪問customer.getId()方法時,該方法直接返回Customer代理類實例的OID值,無需查詢數據庫。由于引用變量 customer始終引用的是沒有被初始化的Customer代理類實例,因此當Session關閉后再執行customer.getName()方法, Hibernate會拋出以下異常:

ERROR LazyInitializer:63 - Exception initializing proxy
net.sf.hibernate.HibernateException: Could not initialize proxy - the owning Session was closed


解決方法:

由于hibernate采用了lazy=true,這樣當你用hibernate查詢時,返回實際為利用cglib增強的代理類,但其并沒有實際填充;當你在前端,利用它來取值(getXXX)時,這時Hibernate才會到數據庫執行查詢,并填充對象,但此時如果和這個代理類相關的session已關閉掉,就會產生種錯誤.
在做一對多時,有時會出現"could not initialize proxy - clothe owning Session was sed,這個好像是hibernate的緩存問題.問題解決:需要在<many-to-one>里設置lazy="false". 但有可能會引發另一個異常叫

failed to lazily initialize a collection of role: XXXXXXXX, no session or session was closed


解決方法:在web.xml中加入
<filter>
?? <filter-name>hibernateFilter</filter-name>
?? <filter-class>
?? org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
?? </filter-class>
</filter
<filter-mapping>
?? <filter-name>hibernateFilter</filter-name>
?? <url-pattern>*.do</url-pattern>
</filter-mapping>
就可以了;

參考了:
Hibernate與延遲加載:

Hibernate對象關系映射提供延遲的與非延遲的對象初始化。非延遲加載在讀取一個對象的時候會將與這個對象所有相關的其他對象一起讀取出來。這有時會導致成百的(如果不是成千的話)select語句在讀取對象的時候執行。這個問題有時出現在使用雙向關系的時候,經常會導致整個數據庫都在初始化的階段被讀出來了。當然,你可以不厭其煩地檢查每一個對象與其他對象的關系,并把那些最昂貴的刪除,但是到最后,我們可能會因此失去了本想在ORM工具中獲得的便利。


一個明顯的解決方法是使用Hibernate提供的延遲加載機制。這種初始化策略只在一個對象調用它的一對多或多對多關系時才將關系對象讀取出來。這個過程對開發者來說是透明的,而且只進行了很少的數據庫操作請求,因此會得到比較明顯的性能提升。這項技術的一個缺陷是延遲加載技術要求一個Hibernate會話要在對象使用的時候一直開著。這會成為通過使用DAO模式將持久層抽象出來時的一個主要問題。為了將持久化機制完全地抽象出來,所有的數據庫邏輯,包括打開或關閉會話,都不能在應用層出現。最常見的是,一些實現了簡單接口的DAO實現類將數據庫邏輯完全封裝起來了。一種快速但是笨拙的解決方法是放棄DAO模式,將數據庫連接邏輯加到應用層中來。這可能對一些小的應用程序有效,但是在大的系統中,這是一個嚴重的設計缺陷,妨礙了系統的可擴展性。

在Web層進行延遲加載

幸運的是,Spring框架為Hibernate延遲加載與DAO模式的整合提供了一種方便的解決方法。對那些不熟悉Spring與Hibernate集成使用的人,我不會在這里討論過多的細節,但是我建議你去了解Hibernate與Spring集成的數據訪問。以一個Web應用為例,Spring提供了OpenSessionInViewFilter和OpenSessionInViewInterceptor。我們可以隨意選擇一個類來實現相同的功能。兩種方法唯一的不同就在于interceptor在Spring容器中運行并被配置在web應用的上下文中,而Filter在Spring之前運行并被配置在web.xml中。不管用哪個,他們都在請求將當前會話與當前(數據庫)線程綁定時打開Hibernate會話。一旦已綁定到線程,這個打開了的Hibernate會話可以在DAO實現類中透明地使用。這個會話會為延遲加載數據庫中值對象的視圖保持打開狀態。一旦這個邏輯視圖完成了,Hibernate會話會在Filter的doFilter方法或者Interceptor的postHandle方法中被關閉。下面是每個組件的配置示例:



Interceptor的配置:


<beans>
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="openSessionInViewInterceptor"/>
</list>
</property>
<property name="mappings">

</bean>

<bean name="openSessionInViewInterceptor"
class="org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
</beans>

Filter的配置


<web-app>

<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate.support.OpenSessionInViewFilter
</filter-class>
</filter>

<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*. spring </url-pattern>
</filter-mapping>

</web-app>


實現Hibernate的Dao接口來使用打開的會話是很容易的。事實上,如果你已經使用了Spring框架來實現你的Hibernate Dao,很可能你不需要改變任何東西。方便的HibernateTemplate公用組件使訪問數據庫變成小菜一碟,而DAO接口只有通過這個組件才可以訪問到數據庫。下面是一個示例的DAO:


public class HibernateProductDAO extends HibernateDaoSupport implements ProductDAO {

public Product getProduct(Integer productId) {
return (Product)getHibernateTemplate().load(Product.class, productId);
}

public Integer saveProduct(Product product) {
return (Integer) getHibernateTemplate().save(product);
}

public void updateProduct(Product product) {
getHibernateTemplate().update(product);
}
}


在業務邏輯層中使用延遲加載

即使在視圖外面,Spring框架也通過使用AOP 攔截器 HibernateInterceptor來使得延遲加載變得很容易實現。這個Hibernate 攔截器透明地將調用配置在Spring應用程序上下文中的業務對象中方法的請求攔截下來,在調用方法之前打開一個Hibernate會話,然后在方法執行完之后將會話關閉。讓我們來看一個簡單的例子,假設我們有一個接口BussinessObject:


public??? interface??? BusinessObject??? {
public??? void??? doSomethingThatInvolvesDaos();
}
類BusinessObjectImpl實現了BusinessObject接口:

public??? class??? BusinessObjectImpl??? implements??? BusinessObject??? {
public??? void??? doSomethingThatInvolvesDaos()??? {
//??? lots of logic that calls
//??? DAO classes Which access
//??? data objects lazily
}
}



通過在Spring應用程序上下文中的一些配置,我們可以讓將調用BusinessObject的方法攔截下來,再令它的方法支持延遲加載。看看下面的一個程序片段:



<beans>
<bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="businessObjectTarget" class="com.acompany.BusinessObjectImpl">
<property name="someDAO"><ref bean="someDAO"/></property>
</bean>
<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"><ref bean="businessObjectTarget"/></property>
<property name="proxyInterfaces">
<value>com.acompany.BusinessObject</value>
</property>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>
</beans>

當businessObject被調用的時候,HibernateInterceptor打開一個Hibernate會話,并將調用請求傳遞給BusinessObjectImpl對象。當BusinessObjectImpl執行完成后,HibernateInterceptor透明地關閉了會話。應用層的代碼不用了解任何持久層邏輯,還是實現了延遲加載。


在單元測試中測試延遲加載

最后,我們需要用J-Unit來測試我們的延遲加載程序。我們可以輕易地通過重寫TestCase類中的setUp和tearDown方法來實現這個要求。我比較喜歡用這個方便的抽象類作為我所有測試類的基類。


public abstract class MyLazyTestCase extends TestCase {

private SessionFactory sessionFactory;
private Session session;

public void setUp() throws Exception {
super.setUp();
SessionFactory sessionFactory = (SessionFactory) getBean("sessionFactory");
session = SessionFactoryUtils.getSession(sessionFactory, true);
Session s = sessionFactory.openSession();
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s));

}

protected Object getBean(String beanName) {
//Code to get objects from Spring application context
}

public void tearDown() throws Exception {
super.tearDown();
SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
Session s = holder.getSession();
s.flush();
TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.closeSessionIfNecessary(s, sessionFactory);
}
} 轉載人QQ:173327103

轉載于:https://blog.51cto.com/nxdxt/59620

總結

以上是生活随笔為你收集整理的hibernate 延迟加载问题探讨的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 四虎国产 | 天天草综合 | 亚洲av电影天堂男人的天堂 | 亚洲 小说区 图片区 | 男女调教视频 | 黄色生活毛片 | 超碰人人干人人 | 日韩美女免费视频 | 精品国产一级片 | 色婷婷狠狠操 | 欧美老熟妇又粗又大 | 日本爽爽爽爽爽爽在线观看免 | 中文字幕日产乱码中 | 日本免费a级片 | 国产高清无密码一区二区三区 | 日本熟妇一区二区三区四区 | 欲求不满在线小早川怜子 | 麻豆av免费在线 | 国产大片黄 | 国产色a | 婷婷久 | 色综合久久中文字幕无码 | 日韩 欧美 精品 | 精品国产三级片在线观看 | 午夜激情一区 | youjizz.com最新 | 国产又爽又黄的激情精品视频 | xxxx色| 欧美精品一区二区三区三州 | 免费在线看黄网站 | 女性裸体视频网站 | 91视频论坛 | 日韩中文字幕在线看 | 日韩亚洲在线 | 美女视频黄色 | 欧美激情视频一区二区 | 肉色丝袜小早川怜子av | 成年人午夜免费视频 | 热久久久久 | 国产又白又嫩又爽又黄 | 韩国伦理片在线看 | 欧美日韩一区在线 | 射进来av影视网 | 国产盗摄一区二区三区在线 | 娇妻之欲海泛舟无弹窗笔趣阁 | 在线播放无码后入内射少妇 | 久久一区二区电影 | 在线观看国产一区 | 91天天爽 | 青青草一区二区 | 美丽姑娘免费观看在线观看 | 亚洲国产一区二区三区 | 天堂网成人 | 国产白嫩美女无套久久 | 少妇又紧又色又爽又刺激 | 久久久久久久精 | 日韩成人中文字幕 | 性盈盈影院中文字幕 | 亚洲一二三级 | 日韩两性视频 | 人体一级片 | 久久韩日 | 日本xxxx高潮少妇 | 国产三级精品三级在线观看 | 8x8x国产精品一区二区 | 狠狠干干干 | 国产精品一区二区久久国产 | 亚洲av鲁丝一区二区三区 | 女人一区二区三区 | 密臀av一区二区 | 蜜桃av噜噜一区二区三区麻豆 | 亚洲乱码少妇 | 日韩精品免费一区二区三区 | 九色porny丨精品自拍视频 | 亚洲欧美日韩天堂 | 性猛交xxxx乱大交3 | 成人一区二区av | 色老大网站 | 国产成人无码一二三区视频 | 国产av人人夜夜澡人人爽麻豆 | 欧洲做受高潮免费看 | 亚洲欧美小视频 | 免费三级在线 | 亚洲精品视频导航 | 欧洲av一区 | 亚洲喷潮| 亚洲伦理影院 | 按摩毛片| 波多野结衣大片 | 人人妻人人藻人人爽欧美一区 | 国产在线视频一区二区三区 | 99久久国产热无码精品免费 | 欧美日韩一区二区三区在线电影 | av综合导航 | 综合激情四射 | 婷婷成人综合网 | 天天色综合影视 | 日韩免费视频一区二区视频在线观看 | 国产成人精品一区二区三区视频 |