在使用 Oracle 數據庫時,SEQUENCE 是生成唯一主鍵的標準機制。Hibernate 通過 sequence 生成器原生支持 Oracle Sequence,無需手寫 SQL 查詢 SELECT seq.nextval FROM dual。本文詳細講解 Sequence 創建、Hibernate 映射配置(XML 與註解)、生成策略選型、常見問題與優化建議。
CREATE SEQUENCE seq_id
MINVALUE 1
START WITH 1
INCREMENT BY 1
CACHE 20; -- 關鍵優化:內存預分配 20 個值,減少字典鎖競爭
-- 可選參數:
-- NOCYCLE -- 達到最大值不循環 (默認)
-- NOORDER -- 不保證順序 (默認,RAC 環境建議 ORDER)
ORDER 保證全局遞增序列,或使用 NOCACHE 避免節點間緩存不一致導致重複(極罕見)。
<id name="id" column="ID0000" type="long">
<generator class="sequence">
<param name="sequence">seq_id</param> <!-- 必須指定 Sequence 名稱 -->
</generator>
</id>
@Entity
@Table(name = "YXJK_WHRYTXL")
public class Contact {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_gen")
@SequenceGenerator(
name = "seq_gen",
sequenceName = "seq_id", // 數據庫 Sequence 名
allocationSize = 20 // **必須與 Sequence CACHE 一致**
)
@Column(name = "ID0000")
private Long id;
// ...
}
關鍵點:allocationSize (默認 50) **必須等於 Oracle Sequence 的 CACHE 值**。不一致會導致 Hibernate 內存分配塊與數據庫實際值脫節,造成主鍵重複或大量跳空。
| 策略 | 適用數據庫 | 原理 | 優點 | 缺點 |
|---|---|---|---|---|
sequence |
Oracle, PostgreSQL, DB2, Firebird, H2 | 調用數據庫 Sequence (NEXTVAL) |
高性能 (可批量預取)、跨表共享、支持批量插入優化 | 需額外創建 Sequence 對象 |
identity |
MySQL, SQL Server, Sybase, PostgreSQL (SERIAL) | 自增列 / IDENTITY 列 | 無需額外對象、簡單 | **不支持批量插入** (每行必須立即查詢生成值)、不支持跨表共享 |
native |
自動適配 | 根據 Dialect 自動選擇 sequence/identity/hilo | 代碼可移植 | 行為隱式,**生產環境建議顯式指定**,避免遷移驚喜 |
hilo |
任意 (需高低位表) | 高低位算法 (Hi/Lo) | 純應用層生成、無數據庫往返 | 算法複雜、調試困難、現已較少用 |
配置正確時,插入實體會生成如下 SQL:
Hibernate: select seq_id.nextval from dual -- 獲取下一個序列值
Hibernate: insert into YXJK.T_YXJK_WHRYTXL (XM0000, ZW0000, LXDH00, SJHM00, DZYJ00, IP0000, ID0000) values (?, ?, ?, ?, ?, ?, ?)
SELECT seq_id.nextval FROM dual 獲取值,設置到實體 id 字段,再執行 INSERT。allocationSize > 1 (對應 Sequence CACHE),Hibernate 會**內存預分配塊**,僅在塊用盡時發起 nextval 調用,**大幅減少數據庫往返**。新版 Hibernate 提供 enhanced-sequence / SequenceStyleGenerator,支持更智能的優化:
@GenericGenerator(
name = "seq_gen",
strategy = "enhanced-sequence",
parameters = {
@Parameter(name = "sequence_name", value = "seq_id"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "20"), // 對應 CACHE
@Parameter(name = "optimizer", value = "pooled-lo") // 或 pooled, hilo, none
}
)
@GeneratedValue(generator = "seq_gen")
| 優化器 | 行為 | 適用場景 |
|---|---|---|
pooled-lo | 內存池化,數據庫值為池**上界**,內存從 上界 - increment_size + 1 開始分配,**推薦**,無重複風險 | 高併發、集群部署 |
pooled | 數據庫值為池**下界**,內存從下界開始分配 | 舊版兼容 |
hilo | 高低位算法 | 極少用 |
none | 無優化,每次查詢數據庫 | 測試/調試 |
最佳實踐:生產環境**強烈建議使用optimizer="pooled-lo"**,配合increment_size = Sequence CACHE,兼顧性能與安全性。
| 現象 | 原因 | 解決 |
|---|---|---|
主鍵重複 (ORA-00001) | allocationSize ≠ Sequence CACHE;多實例共用 Sequence 但無 ORDER;手動插入指定 ID 衝突 | 統一 allocationSize = CACHE;RAC 加 ORDER;業務代碼禁用手動指定 ID |
| 主鍵大幅跳空 (如 1, 21, 41...) | 正常現象:CACHE=20 導致實例重啟丟失緩存值 | **業務通常可接受**,無需修復。極度在意連續性可設 NOCACHE (性能大幅下降) |
| 插入極慢 | Sequence NOCACHE 或 allocationSize=1;網絡延遲高 | 設置合理 CACHE (20-100) 並同步 allocationSize;啟用 pooled-lo 優化器 |
ORA-02289: sequence does not exist | Sequence 名稱拼寫錯誤、大小寫不匹配、Schema 不同 | Oracle 非引用標識符默認大寫,映射配置用大寫 SEQ_ID 或雙引號 "seq_id" |
CREATE SEQUENCE seq_name CACHE 20; (高併發可調大至 50-100)。generator class="sequence" + param name="sequence"。@SequenceGenerator(allocationSize = 20) **等於 CACHE 值**。enhanced-sequence + optimizer="pooled-lo"。遵循以上規範,即可在 Hibernate + Oracle 架構下實現高性能、安全、可維護的主鍵自增方案。