休眠身份,序列和表(序列)生成器
介紹
在我以前的文章中,我談到了不同的數(shù)據(jù)庫(kù)標(biāo)識(shí)符策略。 這篇文章將比較最常見的替代主要關(guān)鍵策略:
- 身份
- 序列
- 表(序列)
身份
IDENTITY類型(包括在SQL:2003標(biāo)準(zhǔn)中)受以下支持:
- SQL服務(wù)器
- MySQL(AUTO_INCREMENT)
- DB2
- 數(shù)據(jù)庫(kù)
IDENTITY生成器允許按需自動(dòng)增加integer / bigint列。 增量過(guò)程發(fā)生在當(dāng)前正在運(yùn)行的事務(wù)之外,因此回滾可能最終丟棄已分配的值(可能會(huì)發(fā)生值差距)。
增量過(guò)程非常有效,因?yàn)樗褂昧藬?shù)據(jù)庫(kù)內(nèi)部的輕量級(jí)鎖定機(jī)制,而不是重量級(jí)的事務(wù)性過(guò)程粒度鎖定。
唯一的缺點(diǎn)是我們無(wú)法在執(zhí)行INSERT語(yǔ)句之前知道新分配的值。 這種限制阻礙了Hibernate采用的“事務(wù)后寫”刷新策略。 因此,Hibernates使用IDENTITY生成器禁用對(duì)實(shí)體的JDBC批處理支持。
對(duì)于以下示例,我們將啟用會(huì)話工廠JDBC批處理:
properties.put("hibernate.order_inserts", "true"); properties.put("hibernate.order_updates", "true"); properties.put("hibernate.jdbc.batch_size", "2");讓我們使用IDENTITY生成策略定義一個(gè)實(shí)體:
@Entity(name = "identityIdentifier") public static class IdentityIdentifier {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id; }持續(xù)存在5個(gè)實(shí)體:
doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {for (int i = 0; i < 5; i++) {session.persist(new IdentityIdentifier());}session.flush();return null;} });將在另一個(gè)查詢之后執(zhí)行一個(gè)查詢(不涉及JDBC批處理):
Query:{[insert into identityIdentifier (id) values (default)][]} Query:{[insert into identityIdentifier (id) values (default)][]} Query:{[insert into identityIdentifier (id) values (default)][]} Query:{[insert into identityIdentifier (id) values (default)][]} Query:{[insert into identityIdentifier (id) values (default)][]}除了禁用JDBC批處理之外,IDENTITY生成器策略不適用于每個(gè)具體類繼承模型的Table ,因?yàn)榭赡艽嬖诙鄠€(gè)具有相同標(biāo)識(shí)符的子類實(shí)體,并且基類查詢最終將檢索具有相同標(biāo)識(shí)符的實(shí)體(甚至(如果屬于不同類型)。
序列
SEQUENCE生成器(在SQL:2003標(biāo)準(zhǔn)中定義)受以下支持:
- 甲骨文
- SQL服務(wù)器
- PostgreSQL的
- DB2
- 數(shù)據(jù)庫(kù)
SEQUENCE是一個(gè)數(shù)據(jù)庫(kù)對(duì)象,它在每個(gè)連續(xù)的請(qǐng)求上生成增量整數(shù)。 SEQUENCES比IDENTIFIER列靈活得多,因?yàn)?#xff1a;
- SEQUENCE是無(wú)表的,并且可以將同一序列分配給多個(gè)列或表
- SEQUENCE可以預(yù)分配值以提高性能
- SEQUENCE可以定義一個(gè)增量步驟,使我們可以受益于“池化” Hilo算法
- SEQUENCE不會(huì)限制Hibernate JDBC批處理
- SEQUENCE不會(huì)限制Hibernate繼承模型
讓我們使用SEQUENCE生成策略定義一個(gè)實(shí)體:
@Entity(name = "sequenceIdentifier") public static class SequenceIdentifier {@Id@GenericGenerator(name = "sequence", strategy = "sequence", parameters = {@org.hibernate.annotations.Parameter(name = "sequenceName", value = "sequence"),@org.hibernate.annotations.Parameter(name = "allocationSize", value = "1"),})@GeneratedValue(generator = "sequence", strategy=GenerationType.SEQUENCE)private Long id; }我使用了“序列”生成器,因?yàn)槲也幌M鸋ibernate代表我們選擇SequenceHiLoGenerator或SequenceStyleGeneGenerator 。
添加5個(gè)實(shí)體:
doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {for (int i = 0; i < 5; i++) {session.persist(new SequenceIdentifier());}session.flush();return null;} });生成以下查詢:
Query:{[call next value for hibernate_sequence][]} Query:{[call next value for hibernate_sequence][]} Query:{[call next value for hibernate_sequence][]} Query:{[call next value for hibernate_sequence][]} Query:{[call next value for hibernate_sequence][]} Query:{[insert into sequenceIdentifier (id) values (?)][1]} {[insert into sequenceIdentifier (id) values (?)][2]} Query:{[insert into sequenceIdentifier (id) values (?)][3]} {[insert into sequenceIdentifier (id) values (?)][4]} Query:{[insert into sequenceIdentifier (id) values (?)][5]}該表中的插入是批量處理的,但是我們知道在插入實(shí)體之前有5個(gè)序列調(diào)用。 這可以通過(guò)使用HILO算法進(jìn)行優(yōu)化。
表(序列)
生成序列還有另一種與數(shù)據(jù)庫(kù)無(wú)關(guān)的替代方法。 一個(gè)或多個(gè)表可用于保存標(biāo)識(shí)符序列計(jì)數(shù)器。 但這意味著要犧牲寫入性能來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)的可移植性。
盡管IDENTITY和SEQUENCES沒有事務(wù),但是使用數(shù)據(jù)庫(kù)表授權(quán)ACID來(lái)同步多個(gè)并發(fā)id生成請(qǐng)求。
通過(guò)使用行級(jí)鎖定,這比IDENTITY或SEQUENCE生成器要高得多的成本,使之成為可能。
必須在單獨(dú)的數(shù)據(jù)庫(kù)事務(wù)中計(jì)算序列,這需要IsolationDelegate機(jī)制,該機(jī)制同時(shí)支持本地(JDBC)和全局(JTA)事務(wù)。
- 對(duì)于本地事務(wù),它必須打開一個(gè)新的JDBC連接,因此對(duì)當(dāng)前的連接池機(jī)制施加了更大的壓力。
- 對(duì)于全局事務(wù),它需要掛起當(dāng)前正在運(yùn)行的事務(wù)。 在生成序列值之后,必須恢復(fù)實(shí)際事務(wù)。 此過(guò)程有其自己的成本,因此可能會(huì)影響整體應(yīng)用程序性能。
讓我們使用TABLE生成策略定義一個(gè)Entity:
@Entity(name = "tableIdentifier") public static class TableSequenceIdentifier {@Id@GenericGenerator(name = "table", strategy = "enhanced-table", parameters = {@org.hibernate.annotations.Parameter(name = "table_name", value = "sequence_table")})@GeneratedValue(generator = "table", strategy=GenerationType.TABLE)private Long id; }我使用了較新的“增強(qiáng)表”生成器,因?yàn)榕f式“表”生成器已被棄用。
添加5個(gè)實(shí)體:
doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {for (int i = 0; i < 5; i++) {session.persist(new TableSequenceIdentifier());}session.flush();return null;} });生成以下查詢:
Query:{[select tbl.next_val from sequence_table tbl where tbl.sequence_name=? for update][default]} Query:{[insert into sequence_table (sequence_name, next_val) values (?,?)][default,1]} Query:{[update sequence_table set next_val=? where next_val=? and sequence_name=?][2,1,default]} Query:{[select tbl.next_val from sequence_table tbl where tbl.sequence_name=? for update][default]} Query:{[update sequence_table set next_val=? where next_val=? and sequence_name=?][3,2,default]} Query:{[select tbl.next_val from sequence_table tbl where tbl.sequence_name=? for update][default]} Query:{[update sequence_table set next_val=? where next_val=? and sequence_name=?][4,3,default]} Query:{[select tbl.next_val from sequence_table tbl where tbl.sequence_name=? for update][default]} Query:{[update sequence_table set next_val=? where next_val=? and sequence_name=?][5,4,default]} Query:{[select tbl.next_val from sequence_table tbl where tbl.sequence_name=? for update][default]} Query:{[update sequence_table set next_val=? where next_val=? and sequence_name=?][6,5,default]} Query:{[insert into tableIdentifier (id) values (?)][1]} {[insert into tableIdentifier (id) values (?)][2]} Query:{[insert into tableIdentifier (id) values (?)][3]} {[insert into tableIdentifier (id) values (?)][4]} Query:{[insert into tableIdentifier (id) values (?)][5]}表生成器允許JDBC批處理,但它依靠SELECT FOR UPDATE查詢。 行級(jí)別鎖定絕對(duì)比使用本機(jī)IDENTITY或SEQUENCE效率低。
因此,根據(jù)您的應(yīng)用程序要求,您可以選擇多個(gè)選項(xiàng)。 沒有一個(gè)單一的獲勝策略,每一個(gè)都有優(yōu)點(diǎn)和缺點(diǎn)。
- 代碼可在GitHub上獲得 。
翻譯自: https://www.javacodegeeks.com/2014/07/hibernate-identity-sequence-and-table-sequence-generator.html
總結(jié)
以上是生活随笔為你收集整理的休眠身份,序列和表(序列)生成器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 14稳定版首批更新机型曝
- 下一篇: 微软:Windows 更新将逐步不再提供