hibernate自动配置_Hibernate自动冲洗的黑暗面
hibernate自動(dòng)配置
介紹
既然我已經(jīng)描述了JPA和Hibernate刷新策略的基礎(chǔ)知識(shí) ,我就可以繼續(xù)闡明Hibernate的AUTO刷新模式的令人驚訝的行為。
并非所有查詢都會(huì)觸發(fā)會(huì)話刷新
許多人會(huì)認(rèn)為Hibernate 總是在執(zhí)行任何查詢之前先刷新Session。 雖然這可能是一種更直觀的方法,并且可能更接近JPA的AUTO FlushModeType ,但是Hibernate嘗試對(duì)其進(jìn)行優(yōu)化。 如果當(dāng)前執(zhí)行的查詢不會(huì)命中未決SQL INSERT / UPDATE / DELETE語句,則不嚴(yán)格要求刷新。
如參考文檔中所述,AUTO刷新策略有時(shí)可能在執(zhí)行查詢之前同步當(dāng)前持久性上下文。 如果框架作者選擇將其命名為FlushMode.SOMETIMES,那將更加直觀。
JPQL / HQL和SQL
與許多其他ORM解決方案一樣,Hibernate提供了一種非常基于SQL-92語法的有限實(shí)體查詢語言( JPQL / HQL )。
當(dāng)前數(shù)據(jù)庫方言將實(shí)體查詢語言轉(zhuǎn)換為SQL,因此它必須在不同的數(shù)據(jù)庫產(chǎn)品中提供相同的功能。 由于大多數(shù)數(shù)據(jù)庫系統(tǒng)都是SQL-92投訴,因此實(shí)體查詢語言是最常見的數(shù)據(jù)庫查詢語法的抽象。
雖然您可以在許多用例(選擇實(shí)體,甚至是投影)中使用實(shí)體查詢語言,但有時(shí)其有限功能與高級(jí)查詢請(qǐng)求不匹配。 每當(dāng)我們想要利用某些特定的查詢技術(shù)時(shí),例如:
- 視窗功能
- 數(shù)據(jù)透視表
- 常用表表達(dá)式
我們別無選擇,只能運(yùn)行本機(jī)SQL查詢。
Hibernate是一個(gè)持久性框架。 Hibernate從未打算取代SQL。 如果在本機(jī)查詢中更好地表達(dá)某些查詢,那么就不應(yīng)該在數(shù)據(jù)庫可移植性的高度上犧牲應(yīng)用程序的性能。
自動(dòng)沖洗和HQL / JPQL
首先,我們將測試將要執(zhí)行HQL查詢時(shí)AUTO刷新模式的行為。 為此,我們定義了以下不相關(guān)的實(shí)體:
該測試將執(zhí)行以下操作:
- 一個(gè)人將被堅(jiān)持。
- 選擇用戶不應(yīng)觸發(fā)刷新。
- 查詢?nèi)藛T時(shí),AUTO刷新應(yīng)觸發(fā)實(shí)體狀態(tài)轉(zhuǎn)換同步(應(yīng)在執(zhí)行選擇查詢之前執(zhí)行人員INSERT)。
提供以下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_][]}如您所見,用戶選擇尚未觸發(fā)會(huì)話刷新。 這是因?yàn)镠ibernate會(huì)根據(jù)掛起的表語句檢查當(dāng)前查詢空間。 如果當(dāng)前正在執(zhí)行的查詢與未刷新的表語句不重疊,則可以安全地忽略刷新。
HQL甚至可以檢測產(chǎn)品沖洗:
- 子選擇 session.persist(product);
assertEquals(0L, session.createQuery("select count(*) " +"from User u " +"where u.favoriteColor in (select distinct(p.color) from Product p)").uniqueResult());
導(dǎo)致正確的沖洗調(diào)用:
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風(fēng)格的連接 session.persist(product);
assertEquals(0L, session.createQuery("select count(*) " +"from User u, Product p " +"where u.favoriteColor = p.color").uniqueResult());
觸發(fā)預(yù)期的沖洗:
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][]}
它起作用的原因是因?yàn)橐褜?shí)體查詢解析并轉(zhuǎn)換為SQL查詢。 Hibernate無法引用不存在的表,因此它始終知道HQL / JPQL查詢將命中的數(shù)據(jù)庫表。
因此,Hibernate僅知道我們?cè)贖QL查詢中顯式引用的那些表。 如果當(dāng)前待處理的DML語句暗示數(shù)據(jù)庫觸發(fā)器或數(shù)據(jù)庫級(jí)聯(lián),則Hibernate將不會(huì)意識(shí)到這些。 因此,即使對(duì)于HQL,AUTO刷新模式也可能導(dǎo)致一致性問題。
自動(dòng)刷新和本機(jī)SQL查詢
當(dāng)涉及本地SQL查詢時(shí),事情變得越來越復(fù)雜。 Hibernate無法解析SQL查詢,因?yàn)樗鼉H支持有限的數(shù)據(jù)庫查詢語法。 許多數(shù)據(jù)庫系統(tǒng)提供了超越Hibernate Entity Query功能的專有功能。
使用本機(jī)SQL查詢查詢Person表不會(huì)觸發(fā)刷新,從而導(dǎo)致不一致問題:
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]}新保留的產(chǎn)品僅在事務(wù)提交期間插入,因?yàn)楸緳C(jī)SQL查詢未觸發(fā)刷新。 這是主要的一致性問題,許多開發(fā)人員很難調(diào)試甚至無法預(yù)見。 這是始終檢查自動(dòng)生成SQL語句的另一個(gè)原因。
即使對(duì)于命名的本機(jī)查詢,也會(huì)觀察到相同的行為:
@NamedNativeQueries(@NamedNativeQuery(name = "product_ids", query = "select id from product") ) assertNull(session.getNamedQuery("product_ids").uniqueResult());因此,即使預(yù)加載了SQL查詢,Hibernate也不會(huì)提取關(guān)聯(lián)的查詢空間以使其與未決的DML語句匹配。
否決當(dāng)前的沖洗策略
即使當(dāng)前會(huì)話定義了默認(rèn)的刷新策略,您也可以始終基于查詢覆蓋它。
查詢刷新模式
ALWAYS模式將在執(zhí)行任何查詢(HQL或SQL)之前刷新持久性上下文。 這次,Hibernate沒有應(yīng)用優(yōu)化,所有待處理的實(shí)體狀態(tài)轉(zhuǎn)換都將與當(dāng)前數(shù)據(jù)庫事務(wù)同步。
assertEquals(product.getId(), session.createSQLQuery("select id from product").setFlushMode(FlushMode.ALWAYS).uniqueResult());指示Hibernate應(yīng)該同步哪些表
您還可以在當(dāng)前正在執(zhí)行SQL查詢上添加同步規(guī)則。 然后,Hibernate將知道在執(zhí)行查詢之前需要同步哪些數(shù)據(jù)庫表。 這對(duì)于二級(jí)緩存也很有用。
assertEquals(product.getId(), session.createSQLQuery("select id from product").addSynchronizedEntityClass(Product.class).uniqueResult());結(jié)論
自動(dòng)刷新模式非常棘手,并且在查詢基礎(chǔ)上解決一致性問題是維護(hù)人員的噩夢(mèng)。 如果決定添加數(shù)據(jù)庫觸發(fā)器,則必須檢查所有Hibernate查詢,以確保它們最終不會(huì)針對(duì)過時(shí)的數(shù)據(jù)運(yùn)行。
我的建議是使用ALWAYS刷新模式,即使Hibernate作者警告我們:
這種策略幾乎總是不必要且效率低下的。
不一致有時(shí)是一些過早沖洗的問題。 當(dāng)混合DML操作和查詢可能會(huì)導(dǎo)致不必要的刷新時(shí),這種情況很難緩解。 在會(huì)話事務(wù)期間,最好在事務(wù)開始時(shí)(當(dāng)沒有待處理的實(shí)體狀態(tài)轉(zhuǎn)換要同步時(shí))和事務(wù)結(jié)束時(shí)(無論如何將刷新當(dāng)前持久性上下文)執(zhí)行查詢。
實(shí)體狀態(tài)轉(zhuǎn)換操作應(yīng)在事務(wù)結(jié)束時(shí)進(jìn)行,以盡量避免將它們與查詢操作交錯(cuò)(因此避免過早的刷新觸發(fā)器)。
翻譯自: https://www.javacodegeeks.com/2014/08/the-dark-side-of-hibernate-auto-flush.html
hibernate自動(dòng)配置
總結(jié)
以上是生活随笔為你收集整理的hibernate自动配置_Hibernate自动冲洗的黑暗面的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 霍廷格对IDwebhost-哪一个更好?
- 下一篇: 电脑cpu图鉴(电脑Cpu图片)