使用身份 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,此时你可能几乎就在你所在的位置。
我正在尝试映射我的域对象以使用新的 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,此时你可能几乎就在你所在的位置。