2012-04-23 100 views
0

爲什麼我不能通過使用@Transactional註釋返回的方法獲得ID爲session.load(product.class,1)的實體對象product.getName()的值?當我以這種方式獲得產品對象時session.createQuery("from Product as product WHERE product.id = 1)一切都很好。休眠對象生命週期

編輯

道法

public Product getProduct(Long id) { 
return (Product) currentSession().load(Product.class, id); 
} 

服務方法

@Transactional 
public Product getProduct(Long id) { 
    return productDao.getProduct(id); 
} 

控制方法 - 它應該發送JSON,但它與錯誤打破上product.getName()org.hibernate.LazyInitializationException: could not initialize proxy - no Session

@RequestMapping(value = "/product",headers="Accept=application/json") 
public @ResponseBody Product getProduct() { 
    Product product = productService.getProduct(new Long(1)); 
    System.out.println(product.getName()); 
    return product; 
} 
+0

你必須告訴一點點。在通過'session.load(product.class,1)'加載產品後調用'product.getName()'時發生了什麼?產品對象是否可能是Product類的緩存實例?你能發佈你的代碼的相關部分嗎? – andih 2012-04-23 19:49:13

回答

0

如果在會話範圍之外訪問未初始化的集合或代理,即擁有集合的實體或對代理的引用處於分離狀態時,Hibernate將拋出A LazyInitializationException

有時代理或集合需要在關閉會話之前進行初始化。您可以通過調用product.getName()或例如強制初始化。但是,這可能會讓代碼讀者感到困惑,而且對於通用代碼來說並不方便。

靜態方法Hibernate.initialize()Hibernate.isInitialized(),提供延遲加載集合或代理的一種便捷方式申請。只要其會話仍處於打開狀態,Hibernate.initialize(product)將強制代理的初始化,即product

您也可以聲明領域的一些是eagely loaded

@Entity 
public class Product { 

    @Id 
    @GeneratedValue 
    private long id; 


    @Basic(fetch=EAGER) 
    private String name; 


} 
+0

也許我沒有具體說明我想要做什麼。我想從數據庫加載產品並將其屬性發送給瀏覽器。什麼是正確的方法來做到這一點? – user1137146 2012-04-23 20:38:39

+1

一種方法是在返回'product'之前將'Hibernate.initialize(product)'行放入DAO中。或者你可以在產品實體上簡單地寫'@ org.hibernate.annotations.Proxy(lazy = false)',它完全禁止延遲加載你的Product實體的所有屬性。 – andih 2012-04-23 20:51:34

-1

當我們在我們的Java code, the instance is considered to be a transient instance中創建實例時,這意味着沒有適當的機制來管理該實例的持久狀態。 但是,一旦we pass a transient instance to the save, update, or saveOrUpdate method of the Hibernate Session,我們認爲瞬態實例已轉換爲持久實例,因爲Hibernate將開始管理該實例的持久狀態。

任何與Hibernate Session關聯的實例都被認爲是一個持久實例。

保存或更新JavaBean並不是獲得持久實例的唯一方法。 已通過get或load方法調用或HQL或條件查詢加載到Hibernate Session中的JavaBean被視爲持久實例,因此,對這些實例狀態的任何更改或更新將會也可以通過Hibernate Session持久化到數據庫。

如果你確實有一個你想從Hibernate控件發佈的實例,你總是可以調用Hibernate Session的evict方法,傳遞你想從Hibernate控件中釋放的實例名稱。當一個實例不再具有由Hibernate Session管理的狀態時,我們稱之爲分離實例,因爲雖然它在數據庫中具有表示,但Hibernate沒有做任何事情來保持實例與基礎持久性存儲的同步。實際上,該實例與數據庫中的相應表示分離。

當然,當我們使用Hibernate時,我們與數據庫的所有交互必須發生在事務的範圍內。默認情況下,當我們調用save或update之類的方法時,我們永遠無法完全確定數據庫中相應的記錄何時更新 - 我們所知道的確實是一旦事務被提交,所有對持久化與Hibernate Session關聯的實例將被保存到數據庫中。當然,由於某種原因,將所有數據保存到數據庫的行爲總是有可能失敗,如果發生這種情況,Hibernate會拋出一個運行時異常。

在這一點上,除了回滾當前事務並關閉休眠會話之外,並沒有太多可以做的事情。此時,之前在Hibernate Session控制下的所有實例都成爲分離對象,並且很可能不再與數據庫同步。在這種情況下,你總是可以開始一個新的事務,並嘗試通過保存或更新調用將它們與Hibernate Session重新關聯來嘗試將已分離的實例恢復爲持久化實例,但最終可能會更好只需向您的客戶端應用程序發送友好的錯誤消息,並從頭開始重新開始任何請求 - 響應循環。 簡單描述了我們在談論瞬態,持久和分離對象時的含義。