2

我在JEE是新的,最近開始學習Spring和Hibernate。我正在嘗試開發RESTful服務來跟蹤具有類別的項目。我有多對多的關聯(一個項目可以有多個類別,一個類別可以有多個項目),三個表格:項目,類別和連接表格item_category。Hibernate的許多一對多延遲初始化例外

我使用MySQL服務器,春天引導1.3.1和Hibernate 4.3

我想現在要做的是讓類別和類別與產品清單的產品清單。我用API編寫了完整的應用程序,並以LazyInitializationException結束。我嘗試了很多方法,但沒有幫助。 (我可以設置獲取類型EAGER,但這不是一個解決方案)。

例如,這是API列出的所有項目:GET /api/item

,這是輸出:(!沒有預期):

產生的原因:org.hibernate.LazyInitializationException:未能懶洋洋>初始化角色的集合:com.sk.itemlist.domain.Item.categories,無法初始化代理 - 在org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)無會話 〜[休眠核心-4.3.10.Final.jar:4.3.10.Final] at org.hibernate.collection.int ernal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)〜[hibernate-core-4.3.10.Final.jar:4.3.10.Final] at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java: 155)〜[冬眠核-4.3.10.Final.jar:4.3.10.Final] 在org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:160)〜[冬眠核-4.3。 10.Final.jar:4.3.10.Final] 在com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:101)〜[傑克遜數據綁定-2.6.5.jar:2.6。 5] 在com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:24)〜[傑克遜數據綁定-2.6.5.jar:2.6.5] 在com.fasterxml.jackson。 databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:693)〜[jackson-da tabind-2.6.5.jar:2.6.5] 在com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675)〜[傑克遜數據綁定-2.6.5.jar:2.6。 5]

,如果你試圖通過ID來獲得所有類別GET /api/category或類別相同的錯誤GET /api/category/1

因此,這裏是我的問題:

  1. 如何擺脫LazyInitializationException中的?我如何配置休眠以重新打開會話?或者我應該在DAO層初始化集合?
  2. 我讀了關於DTO模式,我不完全理解它是什麼,我應該在這裏深入挖掘?
  3. 當我嘗試向項目中插入數據時,我發現問題。它僅插入到項目表中,連接表和類別爲空。我手動將數據添加到數據庫進行測試
  4. 您對整個應用程序的感覺如何?我能在這裏提高或者我應該避免(如果有的話)

最後,我在這裏上傳完整的項目:https://gitlab.com/sksh/ItemList.git
在資源,你可以找到數據庫轉儲用一些隨機數據。使用有效的數據庫憑證更新application.properties。

+0

是'CategoryDaoImpl.java'中的'public Category findByKey(String key)'是你試圖調用哪個方法給你這個異常? –

+0

@Rdx它將它引發到處,findById,listAll等。自從我在「類別」中添加項目列表後,它開始拋出。 – costello

+0

GET/api/category拋出org.hibernate.LazyInitializationException:無法懶惰地初始化一個角色集合:com.sk.itemlist.domain.Category.items,無法初始化代理 - 否會話,反之亦然,如果我試圖獲取所有項目(GET/API /項目),但在這種情況下,它不能初始化類別 – costello

回答

1

會發生什麼事是:

  • 你問冬眠獲取一些項目
  • 休眠帶給他們,但並不能將物品的類別的信息。
  • 當您嘗試在DB會議的工作完成之後(在CollectionSerializer)來訪問這些類別,你會得到異常
  • 你要問Hibernate來,隨着項目一起,使類別相處得youll能然後在會話結束後使用(迭代,列表或其他)。

你應該使用類似的DAO水平..

// fetch a Criteria reference and use join fetching 
Criteria c = currentSession().createCriteria(Item.class); 
c.setFetchMode("categories", FetchMode.JOIN); 
c.add(Restrictions.eq("id", id)); 
Item result = (Item)c.uniqueResult(); 
return result;  

還有其他的方法,比如在項目

@ManyToMany(fetch=FetchType.EAGER) 
private Set<Category> categories = new HashSet<>(); 

宣佈,但它可能會導致性能問題

+0

使用您的建議改變了ItemDaoImpl中的方法findById,現在得到新的異常: 'org.springframework.http.converter.HttpMessageNotWritableException:Could不寫內容:未能延遲初始化角色集合:com.sk.itemlist.domain.Category.items,無法初始化代理 - 無會話(通過引用鏈:com.sk.itemlist.domain.Item [「categories」 ] - > org.hibernate.collection.internal.PersistentSet [0] - > com.sk.itemlist.domain.Category [「itemList」]);' – costello

+1

現在,您在類別perspe莫如。 您的序列化程序會嘗試寫入項目列表。每個項目都有一個類別列表。每個類別都有一個項目列表。依此類推。 您需要決定在表示中取消引用的位置。傑克遜不會自動執行此操作,您必須執行一些操作。 我通常會這樣做:我使用另一組實際由jackson序列化的DTO實現自己要在API中返回的信息,因此我可以控制何時應該在會話之外訪問收集字段 – yugo

+0

因此,我應該使用dto對象與所有需要的信息,而不是實體對象? – costello