Oracle 23c 原生 IDENTITY 列需用 GENERATED ALWAYS AS IDENTITY 建表,配合 Hibernate 6.2+、Spring Data JPA 3.1+ 及 OracleDialect 方言,并禁用 DDL 自动生成,实体中仅用 @GeneratedValue(strategy = GenerationType.IDENTITY) 才能正确识别和返回 ID。
oracle 23c 原生支持 identity 列(从 12cr1 引入,23c 已全面成熟),但 spring data jpa 默认不识别 oracle 的 identity 语义——直接用 @generatedvalue(strategy = generationtype.identity) 会报错或生成 null。必须显式适配。
Oracle 23c 的 IDENTITY 列怎么建才被 JPA 正确识别
建表时必须用标准语法,且不能混用序列+触发器;JPA 只认原生 IDENTITY 属性:
CREATE TABLE user_info (id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name VARCHAR2(50))- 必须带
GENERATED ALWAYS AS IDENTITY,BY DEFAULT不行(Hibernate 6.2+ 才部分支持,Spring Data JPA 3.x 仍不稳定) - 主键列类型推荐
NUMBER,避免INTEGER或PLS_INTEGER—— 后者在 JDBC 层可能映射失败 - 不要手动插入
ID值(除非用OVERRIDING SYSTEM VALUE),否则 Hibernate 插入时会因返回值为空抛NullPointerException
@GeneratedValue(strategy = GenerationType.IDENTITY) 在 Oracle 23c 下为何报错
错误典型现象:org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save() 或插入后 id 为 null。
根本原因:Hibernate 默认的 Oracle 方言(OracleDialect)在旧版本中未启用 IDENTITY 支持,或 Spring Boot 自动配置未切换到兼容模式。
- 确认使用 Hibernate 6.2+ 和 Spring Data JPA 3.1+(对应 Spring Boot 3.2+)
- 在
application.yml中强制指定方言:spring.jpa.database-platform: org.hibernate.dialect.OracleDialect(注意不是Oracle12cDialect或更老的) - 关闭 DDL 自动生成:
spring.jpa.hibernate.ddl-auto: none—— Oracle 的IDENTITY列无法被 Hibernate 正向生成,必须手工建表
实体类里 @Id + @GeneratedValue 的正确写法
仅当数据库已建好 GENERATED ALWAYS AS IDENTITY 列时,以下写法才有效:
@Entity
@Table(name = "user_info")
public class UserInfo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false, nullable = false)
private Long id;
@Column(name = "name")
private String name;
// ...
}
- 去掉
@SequenceGenerator或@GenericGenerator—— 它们走序列路径,和IDENTITY冲突 -
@Column(updatable = false)很关键:防止 Hibernate 尝试更新自增列 - 如果字段名是
ID(全大写),且 Oracle 表定义也是大写,@Column(name = "ID")必须显式写出,否则 Hibernate 可能按小写匹配失败 - 返回的
id值依赖 JDBC 驱动的getGeneratedKeys()支持,确保用ojdbc11.jar(23c 推荐)而非ojdbc8
替代方案:用 SEQUENCE + GenerationType.SEQUENCE 更稳吗
是的,尤其在跨 Oracle 版本或需兼容旧环境时,SEQUENCE 仍是首选。
- 建序列:
CREATE SEQUENCE user_info_seq START WITH 1 INCREMENT BY 1 - 实体写法:
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")+@SequenceGenerator(name = "user_seq", sequenceName = "user_info_seq", allocationSize = 1) - 注意
allocationSize必须与序列的INCREMENT BY一致,否则 Hibernate 缓存会导致跳号 - 这种写法在 MySQL、PostgreSQL、Oracle 上都可运行,只是 Oracle 23c 原生
IDENTITY能省掉序列对象管理
真正容易被忽略的是:Oracle 23c 的 IDENTITY 列在 JDBC 层是否返回生成值,取决于驱动版本和连接参数 retrieveGeneratedKeys=true 是否生效 —— 这个细节不查日志很难定位。


















