在使用 Oracle 時,只需在實體類的主鍵字段上加上 @GeneratedValue 註解,新增數據時即可自動生成主鍵。但項目遷移到 MySQL 後,同樣的配置卻拋出異常:
java.sql.SQLException: Field '***' doesn't have a default value
原始代碼如下:
@Id
@GeneratedValue
@Column(name = "rol_id")
private Long rolId; // ID
許多開發者通過搜索找到如下配置,確能解決報錯:
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "increment")
@Column(name = "rol_id")
private Long rolId; // ID
這樣設置後主鍵確實表現為自增,但其中原理往往不清不楚,且 increment 策略在高併發環境下存在安全隱患。
針對 MySQL 自增主鍵,最標準、最高效的方式是使用 GenerationType.IDENTITY,讓數據庫自行維護自增列:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "rol_id")
private Long rolId;
AUTO_INCREMENT 列,由數據庫保證唯一性與順序性。increment 策略在應用層維護計數器,多實例部署時極易產生重複鍵。| 策略 | 適用場景 | 優缺點 |
|---|---|---|
| AUTO | 跨數據庫項目 | 由 Hibernate 自動選擇,可能退化為 TABLE 策略,效能一般 |
| SEQUENCE | Oracle、PostgreSQL 等支持序列的數據庫 | 需額外創建序列對象,MySQL 不支持 |
| TABLE | 不支持自增/序列的數據庫 | 通過模擬序列表實現,需行鎖,吞吐量低 |
| UUID | 分布式系統、需全局唯一標識 | 長度較大(36字符),索引性能較差,不利於範圍查詢 |
GenerationType.IDENTITY**。Long 而非基本類型 long,便於判斷是否為新對象(id == null)。hibernate.id.new_generator_mappings 統一管理策略。掌握正確的主鍵生成策略,不僅能解決報錯,更能為系統的高併發穩定運行打下基礎。