使用身份 PK 为 Oracle 12c 配置 Grails 3.0.9?

Configure Grails 3.0.9 for Oracle 12c with identity PK?

我正在尝试映射我的域对象以使用新的 Oracle 12c 身份类型主键,在其他一些系统中也称为自动递增。

Hibernate 4 没有 Oracle12cDialect,它只有 Oracle10gDialect。

Oracle10gDialect 有一个名为 supportsIdentityColumns() 的方法,它被硬编码为 return false,因此将我的 GORM 域对象与生成器映射:"identity" 会导致错误提示 Oracle10gDialect 不支持身份生成器。

我不能使用 GORM select 生成器,因为我没有辅助唯一密钥,而且我不能使用 Hibernate 生成的密钥,因为 Hibernate 和其他(外部)插入 tables会生成重叠键。

现有 Oracle 12c DDL 示例:

    create table person (
           id number(10,0) generated by default as identity, 
           version number(10,0) not null, 
           home_address_id number(10,0), 
           name varchar(255) not null, 
           primary key (id)
    );

GORM 对象:

class Person {

    String name
    Address homeAddress

    static mapping = {
        id column: 'person_key', generator: 'identity'
    }

    static constraints = {
        homeAddress nullable: true
    }
}

内存数据库结果(完美运行):

Hibernate: create table person (person_key bigint generated by default as identity, version bigint not null, home_address_id bigint, name varchar(255) not null, primary key (person_key))
Hibernate: alter table person add constraint FK_bemy93e8a8i6nknj4n21m6fub foreign key (home_address_id) references address
Hibernate: insert into person (person_key, version, home_address_id, name) values (null, ?, ?, ?)

Oracle 数据库结果(损坏):

org.hibernate.MappingException: org.hibernate.dialect.Oracle10gDialect does not support identity key generation 

如何让 Grails 3.0.9 与上述 Oracle table 定义一起工作?

Hibernate 5 有 Oracle 12c 方言,特别是添加 "identity" 支持:org.hibernate.dialect.Oracle12cDialect。因此,要么使用 Hibernate 5,要么为 Hibernate 4 编写基于 12c 的自定义方言。

Hibernate 4 无法配置为使用 Oracle 12c 身份密钥生成。

创建自定义 Oracle12cDialect 不允许我们使用身份密钥生成。它需要 Hibernate 4 中没有的额外支持。

有效的方法是坚持使用 Oracle10gDialect 并使用生成器:'sequence-identity' 然后将序列命名为:

static mapping = {
    id column: 'person_key', generator: 'sequence-identity', params:[sequence:'person_seq']
}

除了在 DDL 中使用身份关键字创建 table 之外,这实际上实现了相同的结果。即使我们能够在 table 定义中获得标识关键字,Oracle 也会简单地在后台创建自己的序列,以便在每次插入记录时使用。使用序列标识而不是序列,还避免了插入新行的双重 DB 调用。使用身份序列,插入 DML 是这样的单个调用:

insert into person (person_key, version, home_address_id, name) values (person_seq.nextval, ?, ?, ?)

使用生成器:'sequence' 新记录插入变成两个 DB 调用,如下所示:

select person_seq.nextval from dual;
insert into person (person_key, version, home_address_id, name) values (?, ?, ?, ?)

所以我看到 'identity-sequence' 相对于 'identity' 的唯一缺点就是 Oracle 不会自动跟踪哪个序列用于哪个 table 并在什么时候自动使用它insert 语句中没有提供键值。但即便如此,也可以通过插入前触发器来处理,如果 Hibernate 4 支持 generator: identity,此时你可能几乎就在你所在的位置。