2016-02-21 144 views
0

比方說,我將當前用戶緩存在servlet會話(或類似)中,並獲得「獲取當前用戶的所有書籍」之類的請求。天真,我會去在servlet會話中緩存Hibernate實體

hibernateSession 
.createCriteria(Book.class) 
.add(Restrictions.eq("user", currentUser)) 
.list(); 

和工作原理,但在更復雜的情況(我現在不能重現),我得到一個

TransientObjectException: object references an unsaved transient instance 

所以我想,我應該重視不知怎的,當前用戶到會話。我試圖

currentUser = (User) session.merge(currentUser); 

才發現,它發出數據庫查詢,從而使緩存不超過只存儲ID更好

這樣的緩存可以有效地完成嗎?

回答

2

我也建議只緩存ID而不是整個實體。但是,您正在查找merge(...)或get(...)的load(...)方法intead。 load(...)方法的優點是隻需生成連接到會話的實體而不對數據庫進行查詢。假設沒有其他人可以出現並刪除記錄,以便您知道您的記錄仍然存在,那麼加載方法的缺點(當然存在)與您的用例無關。

https://docs.jboss.org/hibernate/orm/3.5/javadocs/org/hibernate/Session.html#load(java.lang.Class, java.io.Serializable)

這會給你一個對象,你可以用它來查詢作爲你的榜樣

hibernateSession 
.createCriteria(Book.class) 
.add(Restrictions.eq("user", currentUser)) 
.list(); 

要不然,你也可以使用其他實體來設置,而持續

book.setUser(currentUser); 

在我測試過的hibernate版本中,訪問hashCode(),toString()或equals()方法導致實體初始化,包括一個數據庫查詢。但是,如果您只需要使用它來查詢或設置外鍵引用,同時使其他實體持久化,那麼load(Class,Serializable)方法就是您正在尋找的方法。

已編輯 - 如果不存在記錄會發生什麼 您將得到一個ObjectNotFoundException。它擴展了UnresolvableObjectException,它擴展了HibernateException,當然這是一個RuntimeException。這意味着你的代碼退出而笨拙地(除非你要到處捕獲這個異常 - 但當然,這是不是一個合理的解決方案)

org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.yourcode.YourEntity#id that does not exist] 
at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:419) 
at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:154) 
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:143) 
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174) 
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190) 
at com.yourcode.YourEntity_$$_javassist_143.getNonIdentifierMethod(YourEntity_$$_javassist_143.java) 
at com.yourcode.YourBusinessLogic.method(YourBusinessLogic.java:56) 
+0

非常感謝,我想這就是我以後的感受。你可以添加一些有關在使用帶有被刪除實體的'load'時發生的災難的信息嗎?這不是我問題的一部分,但是我從來沒有從Hibernate文檔中理解。 – maaartinus

1

爲什麼不緩存唯一的ID?對於圖書的查詢,你可以簡單地這樣做:

hibernateSession 
.createCriteria(Book.class) 
.add(Restrictions.eq("user.id", currentUserId)) 
.list(); 

如果需要其他原因緩存的用戶對象,你可以簡單地使用currentUser.id,而不是currentUserId

+0

肯定,但'Book'創建我需要的'user'本身。也許我可以使用一些級聯合並...(至今爲止,我避免級聯,因爲我更願意明確說明這一點)。 – maaartinus

+0

合併(或加載)方法仍然具有性能優勢,因爲您只需訪問持久實體以執行某些操作。我猜想在你的應用程序中,審閱圖書清單比創建新書更經常。 –