簡體   English   中英

使用JPA / Hibernate保留大型對象圖時發生異常

[英]Exception while persisting a large object graph using JPA/Hibernate

我們正在創建一個由JPA支持的新Web應用程序,以替換舊的Web應用程序。 作為遷移的一部分,我們正在將舊應用程序的數據庫轉換為新的,更復雜的,由JPA管理的數據庫。

因此,我編寫了一個“腳本”,將舊數據庫轉換為一組JPA實體,然后保存它們。 它是這樣的:

  1. 根據域模型的依賴關系創建轉換順序
  2. 對於每個實體
    1. 對舊版數據庫執行數據庫查詢
    2. 將每個獲取的表行的新對象存儲在內存中的列表中
  3. 以與轉換相同的順序遍歷生成的列表,並保留每個實體。

現在,前兩個步驟運行良好。 堅持之后,我得到了一個例外。 當一個實體與另一實體有關系時,會發生例外。 例如,如果我們的實體之一是Book而另一個實體是Chapter定義與Book@ManyToOne(optional=false)關系。 堅持本章后,將引發異常java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: models.Chapter.book -> models.Book

當然,這表明書的狀態出了點問題:似乎書沒有被設置或尚未被保存。 但是,我可以驗證在Chapter的轉換中正確設置了Book ,並且我還可以驗證在持久化Chapter類型的實體之前EntityManager可以持久存儲Book類型的所有實體。 顯然,我的JPA提供程序的行為不符合預期,並且由於某些原因並未真正保留我的Book對象。

哪種解決方案可以讓我保存已轉換為數據庫的整個對象圖? 我使用Hibernate作為我的JPA提供程序,也使用Spring 3.1注入依賴項和EntityManager

編輯1:一些其他信息:我再次驗證了在各章上調用entityManager.persist() 之前,在每個書對象上都調用了entityManager.persist()。 但是,book對象的id仍然為null,這意味着它沒有正確保留。 即使不使用事務,數據庫也保持為空。

編輯2:因為從上面的文字中我不清楚,所以:書和章的故事只是一個例子 任何引用另一個實體的實體都會發生這種情況。 這就好像我沒有正確使用JPA / Hibernate一樣,而不是沒有正確設置實體的值。

編輯3:核心問題似乎是, 盡管正確保留Book,具有所有正確的注釋,book.getId()仍然為null。 基本上,Hibernate不會在持久保存實體后在其上設置id,這會導致以后需要使用這些實體時出現問題。

我曾經在冬眠時遇到這樣的錯誤。 事實證明,導致問題的原因是對象圖中的圓圈和級聯設置的組合。

已經有一段時間了,因此可能無法完全解決問題,但可能足以跟蹤您的問題:

  1. Hibernate要插入章節 意識到它需要先插入
  2. 要插入 意識到它需要首先插入另一個實體(例如Publisher
  3. 插入發布者並執行在發布上定義的級聯(例如authors
  4. 作者參考了他的lastestBook 由於hibernate在內部已經將該書標記為已處理(在第2步中),因此您不會看到任何異常,表明author.book引用了一個臨時實例。

要找出這是否是您的問題,您可以啟用完整的休眠調試,並遵循休眠在對象圖中采用的路徑。

通過與user1888440的討論,我找到了答案。

該答案的解決方案是Spring @Transactional注釋在我的應用程序中不起作用。 這意味着Hibernate所做的一切都不會在事務上下文中發生。 這意味着Hibernate在持久化后將不會設置ID,這意味着所有轉換都會中斷。

@Transactional不起作用的原因可能是因為我沒有提到一個事實:該腳本是Play 2.0(實際上是2.1)應用程序的一部分,因此是使用SBT構建的。 SBT不使用普通的Java設置來構建應用程序,而是使用Scala編譯器來編譯Java。 我的猜測是,Scala編譯無法與Spring進行@Transactional工作所需的AspectJ配合使用。

相反,我在以編程方式定義的Spring事務 (第11.6節)中執行了此轉換所涉及的所有數據庫工作。 現在一切正常。

檢查hbm文件中主鍵/對象ID的未保存值。如果您已通過hibernate框架自動創建ID,並且將ID放置在某處,則將拋出此錯誤。通過取消選中未保存的值是0,如果將ID設置為0,您會看到此錯誤。

聽起來好像您在繼續之前忘記為每章分配一本書。 即使您已保留Book,也需要將其分配給Chapter實例的#book屬性,然后才能保留Chapter。 這是因為您已將關系指定為非可選關系。 #book永遠不能為null。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM