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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

5个常见的Hibernate异常及其解决方法

發(fā)布時間:2023/12/3 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 5个常见的Hibernate异常及其解决方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

了解如何使用Hibernate輕松解決最常見的問題

Hibernate可能是市場上最受歡迎的JPA實現(xiàn),您可以在許多地方看到它,例如:

  • 您自己使用過的項目數(shù),
  • 需要Hibernate經(jīng)驗的職位數(shù)量,當然還有
  • 互聯(lián)網(wǎng)上發(fā)布的問題和例外數(shù)量

在Takipi,重點是查找和修復異常。 因此,我將重點關(guān)注列表中的最后一點,并與您分享我可能已經(jīng)解決,解釋,寫博客和抱怨的5個Hibernate異常,這是我與Hibernate合作超過15年以來最多的。

盡管他們并沒有為十大例外類型提供支持 ,但谷歌的快速搜索告訴我,我并不是唯一面對這些問題的人。

但是在我們探討不同的例外之前,這篇文章是一篇很長的文章,我在免費備忘單中總結(jié)了最重要的觀點。 您可以在這篇文章的末尾下載它。

1. LazyInitializationException

如果您嘗試在沒有活動會話的情況下嘗試訪問另一個實體的未初始化關(guān)系,則Hibernate會拋出LazyInitializationException。 您可以在以下代碼片段中看到一個簡單的示例。

EntityManager em = emf.createEntityManager(); em.getTransaction().begin();Author a = em.find(Author.class, 1L);em.getTransaction().commit(); em.close();log.info(a.getFirstName() + " " + a.getLastName() + " wrote "+a.getBooks().size() + " books.");

好的,您現(xiàn)在可能會說您永遠不會那樣做。 盡管您可能永遠不會在應用程序中使用完全相同的代碼是正確的,但您可以無意間輕松地執(zhí)行相同的操作。

最受歡迎的方法是在您的業(yè)務層中未初始化的演示層中訪問與FetchType.LAZY的關(guān)系。 您可以在受歡迎的論壇中找到很多此類問題,并提出了許多不良的解決方法。

請不要在視圖反模式中使用打開的會話。 它造成的危害更大,然后才帶來收益。

修復LazyInitializationException的最佳方法是在業(yè)務層中初始化所需的關(guān)系。 但是不要僅僅因為可能有一個客戶需要其中之一就初始化所有關(guān)系。 出于性能原因,您應該只初始化所需的關(guān)系。

JPA和Hibernate提供了不同的選項來初始化延遲獲取的關(guān)系 。 我個人最喜歡的是@NamedEntityGraph ,它提供了獨立于查詢的方式來定義將隨查詢獲取的實體圖。

您可以在以下代碼段中看到一個簡單圖形的示例。 它獲取一個Author實體的Book關(guān)系。

@NamedEntityGraph(name = "graph.AuthorBooks", attributeNodes = @NamedAttributeNode("books"))

您可以在Hibernate可用的任何文件中定義@NamedEntityGraph。 我更喜歡在打算與之一起使用的實體上進行操作。

如您所見,定義圖形不需要做太多的事情。 您只需要提供名稱和@NamedAttributeNode批注的數(shù)組即可定義Hibernate從數(shù)據(jù)庫中獲取的屬性。 在此示例中,只有book屬性將關(guān)系映射到Book實體。

然后,您可以提供此圖作為Hibernate的提示,以定義應使用給定查詢初始化的關(guān)系。 您可以在以下代碼段中看到一個示例。

EntityManager em = emf.createEntityManager(); em.getTransaction().begin();EntityGraph<?> graph = em.getEntityGraph("graph.AuthorBooks"); HashMap<String, Object> properties = new HashMap<>(); properties.put("javax.persistence.fetchgraph", graph);Author a = em.find(Author.class, 1L, properties);em.getTransaction().commit(); em.close();log.info(a.getFirstName() + " " + a.getLastName() + " wrote "+a.getBooks().size() + " books.");

如您所見,我首先在EntityManager上調(diào)用getEntityGraph(String name)方法以獲取實體圖的實例。 在下一步中,我將創(chuàng)建帶有查詢提示的HashMap并將該圖添加為javax.persistence.fetchgraph。

在最后一步中,我將查詢提示作為find方法的附加參數(shù)。 這告訴Hibernate初始化與Book實體的關(guān)系,并且我可以在沒有活動的Hibernate會話的情況下調(diào)用getBooks()方法。

2. OptimisticLockException

另一個非常常見的異常是OptimisticLockException。 當您使用樂觀鎖定并檢測到實體的更新沖突時,Hibernate會拋出該錯誤。 發(fā)生這種情況最常見的原因有兩個:

  • 2個用戶嘗試在幾乎相同的時間點更新同一實體。
  • 1個用戶對同一實體執(zhí)行了2次更新,并且您沒有刷新客戶端中的實體表示,因此第一次更新后版本值未更新。
  • 在下面的代碼片段中,您可以看到具有2個并發(fā)更新的測試用例。

    // EntityManager and transaction 1 EntityManager em = emf.createEntityManager(); em.getTransaction().begin();// EntityManager and transaction 2 EntityManager em2 = emf.createEntityManager(); em2.getTransaction().begin();// update 1 Author a = em.find(Author.class, 1L); a.setFirstName("changed");// update 2 Author a2 = em2.find(Author.class, 1L); a2.setFirstName("changed");// commit transaction 1 em.getTransaction().commit(); em.close();// commit transaction 2 try {em2.getTransaction().commit();Assert.fail();} catch (RollbackException e) {Assert.assertTrue(e.getCause() instanceof OptimisticLockException);log.info("2nd transaction failed with an OptimisticLockException");}em2.close();

    如您所見,我使用兩個獨立的EntityManager,并使用它們兩個啟動事務,獲取ID為1的Author實體,并更新名字屬性。

    在我嘗試提交第二個事務并為該Author實體的并發(fā)更新進行Hibernate檢查之前,該方法可以正常工作。 當然,在實際應用中,這將通過兩次并行調(diào)用同一方法來完成。

    如果使用Takipi ,則可以在發(fā)生異常時查看所有變量的狀態(tài),這對于識別第二個更新調(diào)用的來源很有用。

    Takipi的錯誤分析屏幕

    在不引入悲觀鎖定的情況下,您無法做很多事情來避免這種異常,這會犧牲您的應用程序的性能。 只需嘗試盡可能頻繁地更新客戶端中的實體表示,并保持更新操作越短越好。 那應該避免大多數(shù)不必要的OptimisticLockException,并且您需要在客戶端應用程序中處理其余的剩余部分。

    但是,如果只有一個用戶自己導致OptimisticLockException,那么您會發(fā)現(xiàn)一個可以輕松修復的錯誤。 如果您使用樂觀鎖定,則Hibernate將使用version列來跟蹤實體的當前版本并防止并發(fā)修改。 因此,您需要確保在用戶觸發(fā)實體上的任何更改后,客戶端始終更新其對實體的表示。 而且,您的客戶端應用程序也不應緩存實體或代表它的任何值對象。

    3. org.hibernate.AnnotationException:未知的Id.generator

    這是由錯誤的實體映射引起的,在開發(fā)過程中可能會遇到它。 原因很簡單,您可以在@GeneratedValue批注中引用未知的序列生成器,如下面的代碼片段所示。

    @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "authorSequence") @Column(name = "id", updatable = false, nullable = false) private Long id;

    @GeneratedValue批注允許您定義主鍵值的生成策略。 在前面的代碼片段中,我想使用數(shù)據(jù)庫序列,并提供“ authorSequence”作為生成器的名稱。

    現(xiàn)在,許多開發(fā)人員期望“ authorSequence”將成為Hibernate將使用的數(shù)據(jù)庫序列的名稱。 事實并非如此。 這是@SequenceGenerator的名稱,可用于提供有關(guān)Hibernate將使用的數(shù)據(jù)庫序列的更多信息。

    但是@SequenceGenerator的定義丟失了,因此Hibernate引發(fā)了AnnotationException。 要解決此問題,您必須像在以下代碼片段中一樣添加一個@SequenceGenerator批注。

    @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "authorSequence") @SequenceGenerator(name = "authorSequence", sequenceName = "author_seq", initialValue = 1000) @Column(name = "id", updatable = false, nullable = false) private Long id;

    @SequenceGenerator批注允許您提供有關(guān)數(shù)據(jù)庫序列以及Hibernate如何使用它的更多信息。 在此代碼段中,我設置了序列的名稱,即“ author_seq”,并將其初始值設置為1000。

    您還可以指定序列所屬的數(shù)據(jù)庫模式以及Hibernate可以用于性能優(yōu)化的分配大小。 您可以在以下文章中了解有關(guān)ID生成器的更多信息 。

    4. QuerySyntaxException:表未映射

    這是另一個典型的映射錯誤。 在大多數(shù)項目中,數(shù)據(jù)庫架構(gòu)已經(jīng)存在或獨立于您的實體映射定義。 那是一件好事。 請正確設計數(shù)據(jù)庫模式,不要讓Hibernate為您生成它!

    如果您希望Hibernate在啟動時設置數(shù)據(jù)庫,最好提供一個SQL腳本,而不是讓Hibernate根據(jù)您的實體映射生成數(shù)據(jù)庫架構(gòu)。

    現(xiàn)在,回到QuerySyntaxException。 如果數(shù)據(jù)庫模式是獨立于您的實體定義的,則通常會遇到以下情況:默認表名與現(xiàn)有表的名稱不匹配,或者該表是其他數(shù)據(jù)庫模式的一部分。

    在這種情況下,可以為架構(gòu)和表名提供@Table批注,如以下代碼片段所示。

    @Entity @Table(name = "author", schema = "bookstore") public class Author implements Serializable {… }

    5. org.hibernate.PersistentObjectException:分離的實體傳遞給持久化

    此列表中的最后一個異常可能有多種原因,并且都是錯誤:

  • 您嘗試保留一個新實體并提供主鍵值,但是實體映射定義了一種生成它的策略。
  • 您嘗試保留一個新實體,并且持久性上下文已經(jīng)包含具有給定ID的實體。
  • 您嘗試保留一個分離的實體而不是合并它。
  • 第一個很容易修復,不提供主鍵值或刪除主鍵生成策略。

    僅當您自己管理主鍵值并且您的算法創(chuàng)建重復項時,才會發(fā)生第二種情況。 解決此問題的首選方法是讓Hibernate使用數(shù)據(jù)庫序列生成主鍵值,而不是實現(xiàn)自己的算法。

    這并非總是可能的,在這種情況下,您必須測試和調(diào)試用于生成主鍵值的算法。 根據(jù)算法的不同,這可能是一項繁瑣且耗時的任務。

    第三種經(jīng)常發(fā)生在您在客戶端中使用實體時,客戶端調(diào)用了錯誤的服務器方法,該方法將保留新實體而不是更新現(xiàn)有實體。 解決此錯誤的明顯方法是修復客戶端中的呼叫。

    另外,您可以在服務器端執(zhí)行某些操作來避免此類問題,例如使用特定的值對象創(chuàng)建用例,而不是在同一服務器方法中處理創(chuàng)建和更新用例。 這使客戶開發(fā)人員更容易找到并調(diào)用正確的方法,并避免了此類問題。

    摘要和備忘單

    這些是我最常遇到的5個Hibernate Exception,以及如何修復它們。 如您所見,異常及其原因非常不同。 其中一些僅在開發(fā)期間發(fā)生,而另一些會在生產(chǎn)中對您造成打擊。 因此,最好提防并確保您熟悉這些問題。 為了讓您更輕松,我準備了一份備忘單,解釋了本文中提到的5個例外 。

    翻譯自: https://www.javacodegeeks.com/2016/06/5-common-hibernate-exceptions-fix.html

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結(jié)

    以上是生活随笔為你收集整理的5个常见的Hibernate异常及其解决方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。