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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

hibernate自动配置_Hibernate自动冲洗的黑暗面

發布時間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hibernate自动配置_Hibernate自动冲洗的黑暗面 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

hibernate自動配置

介紹

既然我已經描述了JPA和Hibernate刷新策略的基礎知識 ,我就可以繼續闡明Hibernate的AUTO刷新模式的令人驚訝的行為。

并非所有查詢都會觸發會話刷新

許多人會認為Hibernate 總是在執行任何查詢之前先刷新Session。 雖然這可能是一種更直觀的方法,并且可能更接近JPA的AUTO FlushModeType ,但是Hibernate嘗試對其進行優化。 如果當前執行的查詢不會命中未決SQL INSERT / UPDATE / DELETE語句,則不嚴格要求刷新。

如參考文檔中所述,AUTO刷新策略有時可能在執行查詢之前同步當前持久性上下文。 如果框架作者選擇將其命名為FlushMode.SOMETIMES,那將更加直觀。

JPQL / HQL和SQL

與許多其他ORM解決方案一樣,Hibernate提供了一種非常基于SQL-92語法的有限實體查詢語言( JPQL / HQL )。

當前數據庫方言將實體查詢語言轉換為SQL,因此它必須在不同的數據庫產品中提供相同的功能。 由于大多數數據庫系統都是SQL-92投訴,因此實體查詢語言是最常見的數據庫查詢語法的抽象。

雖然您可以在許多用例(選擇實體,甚至是投影)中使用實體查詢語言,但有時其有限功能與高級查詢請求不匹配。 每當我們想要利用某些特定的查詢技術時,例如:

  • 視窗功能
  • 數據透視表
  • 常用表表達式

我們別無選擇,只能運行本機SQL查詢。

Hibernate是一個持久性框架。 Hibernate從未打算取代SQL。 如果在本機查詢中更好地表達某些查詢,那么就不應該在數據庫可移植性的高度上犧牲應用程序的性能。

自動沖洗和HQL / JPQL

首先,我們將測試將要執行HQL查詢時AUTO刷新模式的行為。 為此,我們定義了以下不相關的實體:

該測試將執行以下操作:

  • 一個人將被堅持。
  • 選擇用戶不應觸發刷新。
  • 查詢人員時,AUTO刷新應觸發實體狀態轉換同步(應在執行選擇查詢之前執行人員INSERT)。
Product product = new Product(); session.persist(product); assertEquals(0L, session.createQuery("select count(id) from User").uniqueResult()); assertEquals(product.getId(), session.createQuery("select p.id from Product p").uniqueResult());

提供以下SQL輸出:

[main]: o.h.e.i.AbstractSaveEventListener - Generated identifier: f76f61e2-f3e3-4ea4-8f44-82e9804ceed0, using strategy: org.hibernate.id.UUIDGenerator Query:{[select count(user0_.id) as col_0_0_ from user user0_][]} Query:{[insert into product (color, id) values (?, ?)][12,f76f61e2-f3e3-4ea4-8f44-82e9804ceed0]} Query:{[select product0_.id as col_0_0_ from product product0_][]}

如您所見,用戶選擇尚未觸發會話刷新。 這是因為Hibernate會根據掛起的表語句檢查當前查詢空間。 如果當前正在執行的查詢與未刷新的表語句不重疊,則可以安全地忽略刷新。

HQL甚至可以檢測產品沖洗:

  • 子選擇 session.persist(product); assertEquals(0L, session.createQuery("select count(*) " +"from User u " +"where u.favoriteColor in (select distinct(p.color) from Product p)").uniqueResult());

    導致正確的沖洗調用:

    Query:{[insert into product (color, id) values (?, ?)][Blue,2d9d1b4f-eaee-45f1-a480-120eb66da9e8]} Query:{[select count(*) as col_0_0_ from user user0_ where user0_.favoriteColor in (select distinct product1_.color from product product1_)][]}
  • 或theta風格的連接 session.persist(product); assertEquals(0L, session.createQuery("select count(*) " +"from User u, Product p " +"where u.favoriteColor = p.color").uniqueResult());

    觸發預期的沖洗:

    Query:{[insert into product (color, id) values (?, ?)][Blue,4af0b843-da3f-4b38-aa42-1e590db186a9]} Query:{[select count(*) as col_0_0_ from user user0_ cross join product product1_ where user0_.favoriteColor=product1_.color][]}

它起作用的原因是因為已將實體查詢解析并轉換為SQL查詢。 Hibernate無法引用不存在的表,因此它始終知道HQL / JPQL查詢將命中的數據庫表。

因此,Hibernate僅知道我們在HQL查詢中顯式引用的那些表。 如果當前待處理的DML語句暗示數據庫觸發器或數據庫級聯,則Hibernate將不會意識到這些。 因此,即使對于HQL,AUTO刷新模式也可能導致一致性問題。

自動刷新和本機SQL查詢

當涉及本地SQL查詢時,事情變得越來越復雜。 Hibernate無法解析SQL查詢,因為它僅支持有限的數據庫查詢語法。 許多數據庫系統提供了超越Hibernate Entity Query功能的專有功能。

使用本機SQL查詢查詢Person表不會觸發刷新,從而導致不一致問題:

Product product = new Product(); session.persist(product); assertNull(session.createSQLQuery("select id from product").uniqueResult());DEBUG [main]: o.h.e.i.AbstractSaveEventListener - Generated identifier: 718b84d8-9270-48f3-86ff-0b8da7f9af7c, using strategy: org.hibernate.id.UUIDGenerator Query:{[select id from product][]} Query:{[insert into product (color, id) values (?, ?)][12,718b84d8-9270-48f3-86ff-0b8da7f9af7c]}

新保留的產品僅在事務提交期間插入,因為本機SQL查詢未觸發刷新。 這是主要的一致性問題,許多開發人員很難調試甚至無法預見。 這是始終檢查自動生成SQL語句的另一個原因。

即使對于命名的本機查詢,也會觀察到相同的行為:

@NamedNativeQueries(@NamedNativeQuery(name = "product_ids", query = "select id from product") ) assertNull(session.getNamedQuery("product_ids").uniqueResult());

因此,即使預加載了SQL查詢,Hibernate也不會提取關聯的查詢空間以使其與未決的DML語句匹配。

否決當前的沖洗策略

即使當前會話定義了默認的刷新策略,您也可以始終基于查詢覆蓋它。

查詢刷新模式

ALWAYS模式將在執行任何查詢(HQL或SQL)之前刷新持久性上下文。 這次,Hibernate沒有應用優化,所有待處理的實體狀態轉換都將與當前數據庫事務同步。

assertEquals(product.getId(), session.createSQLQuery("select id from product").setFlushMode(FlushMode.ALWAYS).uniqueResult());

指示Hibernate應該同步哪些表

您還可以在當前正在執行SQL查詢上添加同步規則。 然后,Hibernate將知道在執行查詢之前需要同步哪些數據庫表。 這對于二級緩存也很有用。

assertEquals(product.getId(), session.createSQLQuery("select id from product").addSynchronizedEntityClass(Product.class).uniqueResult());

結論

自動刷新模式非常棘手,并且在查詢基礎上解決一致性問題是維護人員的噩夢。 如果決定添加數據庫觸發器,則必須檢查所有Hibernate查詢,以確保它們最終不會針對過時的數據運行。

我的建議是使用ALWAYS刷新模式,即使Hibernate作者警告我們:

這種策略幾乎總是不必要且效率低下的。

不一致有時是一些過早沖洗的問題。 當混合DML操作和查詢可能會導致不必要的刷新時,這種情況很難緩解。 在會話事務期間,最好在事務開始時(當沒有待處理的實體狀態轉換要同步時)和事務結束時(無論如何將刷新當前持久性上下文)執行查詢。

實體狀態轉換操作應在事務結束時進行,以盡量避免將它們與查詢操作交錯(因此避免過早的刷新觸發器)。

翻譯自: https://www.javacodegeeks.com/2014/08/the-dark-side-of-hibernate-auto-flush.html

hibernate自動配置

總結

以上是生活随笔為你收集整理的hibernate自动配置_Hibernate自动冲洗的黑暗面的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。