Hibernate隐藏的宝石:pooled-lo优化器
介紹
在這篇文章中,我們將揭示一個序列標(biāo)識符生成器,??它結(jié)合了標(biāo)識符分配效率和與其他外部系統(tǒng)的互操作性(同時訪問底層數(shù)據(jù)庫系統(tǒng))。
傳統(tǒng)上,有兩種序列標(biāo)識符策略可供選擇。
- 序列標(biāo)識符,對于每個新值分配總是命中數(shù)據(jù)庫。 即使使用數(shù)據(jù)庫序列預(yù)分配,我們也要花費大量的數(shù)據(jù)庫往返費用。
- seqhilo標(biāo)識符,使用hi / lo算法。 該生成器在內(nèi)存中計算一些標(biāo)識符值,因此減少了數(shù)據(jù)庫往返調(diào)用。 這種優(yōu)化技術(shù)的問題在于當(dāng)前的數(shù)據(jù)庫序列值不再反映當(dāng)前的最高內(nèi)存生成值。 數(shù)據(jù)庫序列用作存儲區(qū)編號,這使得其他系統(tǒng)很難與所討論的數(shù)據(jù)庫表進(jìn)行互操作。 其他應(yīng)用程序必須了解高/低標(biāo)識符策略的內(nèi)部工作方式,才能正確生成非沖突標(biāo)識符。
增強的標(biāo)識符
Hibernate提供了一類新的標(biāo)識符生成器 ,解決了原始標(biāo)識符生成器的許多缺點。 增強的標(biāo)識符生成器沒有固定的標(biāo)識符分配策略。 優(yōu)化策略是可配置的,我們甚至可以提供自己的優(yōu)化實現(xiàn)。 默認(rèn)情況下,Hibernate帶有以下內(nèi)置優(yōu)化器 :
- none :每個標(biāo)識符都是從數(shù)據(jù)庫中獲取的,因此等效于原始序列生成器。
- hi / lo :它使用hi / lo算法,與原始seqhilo生成器等效。
- 合并的 :此優(yōu)化器使用高/低優(yōu)化策略,但是當(dāng)前內(nèi)存中標(biāo)識符的最高邊界是從實際數(shù)據(jù)庫序列值中提取的。
- pooled-lo :它類似于池優(yōu)化器,但是數(shù)據(jù)庫序列值用作當(dāng)前的內(nèi)存最低邊界
在正式發(fā)布公告中 , 公告了合并的優(yōu)化器可與其他外部系統(tǒng)進(jìn)行互操作:
即使其他應(yīng)用程序也在插入值,我們也將是絕對安全的,因為SEQUENCE本身將處理應(yīng)用此增量大小。
這實際上是我們正在尋找的東西; 當(dāng)其他外部系統(tǒng)在同一數(shù)據(jù)庫表中同時插入行時,標(biāo)識符生成器既高效又不會沖突。
測試時間
以下測試將檢查新的優(yōu)化器如何與其他外部數(shù)據(jù)庫表插入配合使用。 在我們的情況下,外部系統(tǒng)將是同一數(shù)據(jù)庫表/序列上的一些本機JDBC插入語句。
doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {for (int i = 0; i < 8; i++) {session.persist(newEntityInstance());}session.flush();assertEquals(8, ((Number) session.createSQLQuery("SELECT COUNT(*) FROM sequenceIdentifier").uniqueResult()).intValue());insertNewRow(session);insertNewRow(session);insertNewRow(session);assertEquals(11, ((Number) session.createSQLQuery("SELECT COUNT(*) FROM sequenceIdentifier").uniqueResult()).intValue());List<Number> ids = session.createSQLQuery("SELECT id FROM sequenceIdentifier").list();for (Number id : ids) {LOGGER.debug("Found id: {}", id);}for (int i = 0; i < 3; i++) {session.persist(newEntityInstance());}session.flush();return null;} });池優(yōu)化器
我們將首先使用池優(yōu)化器策略:
@Entity(name = "sequenceIdentifier") public static class PooledSequenceIdentifier {@Id@GenericGenerator(name = "sequenceGenerator", strategy = "enhanced-sequence",parameters = {@org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled"),@org.hibernate.annotations.Parameter(name = "initial_value", value = "1"),@org.hibernate.annotations.Parameter(name = "increment_size", value = "5")})@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")private Long id; }運行測試最終會引發(fā)以下異常:
DEBUG [main]: n.t.d.l.SLF4JQueryLoggingListener - Name: Time:0 Num:1 Query:{[insert into sequenceIdentifier (id) values (?)][9]} DEBUG [main]: n.t.d.l.SLF4JQueryLoggingListener - Name: Time:0 Num:1 Query:{[insert into sequenceIdentifier (id) values (?)][10]} DEBUG [main]: n.t.d.l.SLF4JQueryLoggingListener - Name: Time:0 Num:1 Query:{[insert into sequenceIdentifier (id) values (?)][26]} WARN [main]: o.h.e.j.s.SqlExceptionHelper - SQL Error: -104, SQLState: 23505 ERROR [main]: o.h.e.j.s.SqlExceptionHelper - integrity constraint violation: unique constraint or index violation; SYS_PK_10104 table: SEQUENCEIDENTIFIER ERROR [main]: c.v.h.m.l.i.PooledSequenceIdentifierTest - Pooled optimizer threw org.hibernate.exception.ConstraintViolationException: could not execute statementat org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:72) ~[hibernate-core-4.3.5.Final.jar:4.3.5.Final] Caused by: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: unique constraint or index violation; SYS_PK_10104 table: SEQUENCEIDENTIFIERat org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source) ~[hsqldb-2.3.2.jar:2.3.2]我不確定這是錯誤還是僅是設(shè)計限制,但是合并的優(yōu)化器不滿足互操作性要求。
為了可視化發(fā)生的情況,我在下圖中總結(jié)了序列調(diào)用:
當(dāng)池優(yōu)化器檢索當(dāng)前序列值時,它將使用它來計算最低的內(nèi)存邊界。 最小值是實際的先前序列值,并且該值可能已被其他一些外部INSERT語句使用。
Pool-lo優(yōu)化器
幸運的是,還有另外一個要測試的優(yōu)化器(參考文檔中未提及)。 pool-lo優(yōu)化器使用當(dāng)前數(shù)據(jù)庫序列值作為最低的內(nèi)存邊界,因此其他系統(tǒng)可以自由使用下一個序列值而不會冒標(biāo)識符沖突的風(fēng)險:
@Entity(name = "sequenceIdentifier") public static class PooledLoSequenceIdentifier {@Id@GenericGenerator(name = "sequenceGenerator", strategy = "enhanced-sequence",parameters = {@org.hibernate.annotations.Parameter(name = "optimizer",value = "pooled-lo"),@org.hibernate.annotations.Parameter(name = "initial_value", value = "1"),@org.hibernate.annotations.Parameter(name = "increment_size", value = "5")})@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")private Long id; }為了更好地了解此優(yōu)化器的內(nèi)部工作原理,下圖總結(jié)了標(biāo)識符分配過程:
結(jié)論
一顆隱藏的寶石是大多數(shù)人甚至都不知道其存在的巨大特征之一。 pool-lo優(yōu)化器非常有用,但是大多數(shù)人甚至都不知道它的存在。
- 代碼可在GitHub上獲得 。
翻譯自: https://www.javacodegeeks.com/2014/07/hibernate-hidden-gem-the-pooled-lo-optimizer.html
總結(jié)
以上是生活随笔為你收集整理的Hibernate隐藏的宝石:pooled-lo优化器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux查看服务器硬件配置(linux
- 下一篇: 仍不切换到Java 8的6个理由