我正在努力 Java的 应用程序,应该做CRUD操作(使用 过冬 4.3.8)在具有相同数据库模式的两个不同数据库上。
有一个 MySQL的 (版本5.1.73)和 神谕 (11g Express Edition Release 11.2.0.2.0 - 64bit)数据库。
Java类用 JPA注释 是使用Hibernate代码生成从数据库表生成的。
问题是我们现在需要使用自动主键生成和MySQL使用 GenerationType.IDENTITY 和Oracle使用 GenerationType.SEQUENCE。此外,我们需要能够在极少数情况下自己手动设置主键。
注释类中的followig代码适用于两个数据库的自动密钥生成,但如果主键是自设置则失败。
@GeneratedValue(strategy=GenerationType.AUTO, generator="sequence_generator")
@SequenceGenerator(name="sequence_generator", sequenceName="SEQUENCE1")
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
没有 @GeneratedValue 和 @SequenceGenerator 注释可以手动设置主键,但自动生成不起作用。
即使你用过 GenerationType.AUTO
如果没有任何SEQUENCE特定参数,您将无法保存指定的标识符。
如果您愿意做出一些妥协,有一些解决方法:
一种方法是切换到指定的标识符。您可以使用 UUID 标识符,适用于MySQL和Oracle,您也可以手动分配值。
另一种方法是使用自定义表生成器。
首先定义一个可识别的接口:
public interface Identifiable<T extends Serializable> {
T getId();
}
然后扩展表生成器:
public class AssignedTableGenerator extends TableGenerator {
@Override
public Serializable generate(SessionImplementor session, Object obj) {
if(obj instanceof Identifiable) {
Identifiable identifiable = (Identifiable) obj;
Serializable id = identifiable.getId();
if(id != null) {
return id;
}
}
return super.generate(session, obj);
}
}
此生成器能够将分配的标识符与合成生成的标识符混合:
doInTransaction(session -> {
for (int i = 0; i < 5; i++) {
session.persist(new AssignTableSequenceIdentifier());
}
AssignTableSequenceIdentifier tableSequenceIdentifier = new AssignTableSequenceIdentifier();
tableSequenceIdentifier.id = -1L;
session.merge(tableSequenceIdentifier);
session.flush();
});
生成以下语句:
select tbl.next_val from sequence_table tbl where tbl.sequence_name=default for update
insert into sequence_table (sequence_name, next_val) values (default,1)
update sequence_table set next_val=2 where next_val=1 and sequence_name=default
select tbl.next_val from sequence_table tbl where tbl.sequence_name=default for update
update sequence_table set next_val=3 where next_val=2 and sequence_name=default
select tbl.next_val from sequence_table tbl where tbl.sequence_name=default for update
update sequence_table set next_val=4 where next_val=3 and sequence_name=default
select tbl.next_val from sequence_table tbl where tbl.sequence_name=default for update
update sequence_table set next_val=5 where next_val=4 and sequence_name=default
select tbl.next_val from sequence_table tbl where tbl.sequence_name=default for update
update sequence_table set next_val=6 where next_val=5 and sequence_name=default
select identityvs0_.id as id1_0_0_ from assigneTableIdentifier identityvs0_ where identityvs0_.id=-1
insert into assigneTableIdentifier (id) values (1, 2)
insert into assigneTableIdentifier (id) values (2, 4)
insert into assigneTableIdentifier (id) values (5, -1)
对于Oracle,您可以组合SEQUENCE和指定的生成器,如中所述 本文。
简而言之,考虑以下发电机:
public class AssignedSequenceStyleGenerator
extends SequenceStyleGenerator {
@Override
public Serializable generate(SessionImplementor session,
Object obj) {
if(obj instanceof Identifiable) {
Identifiable identifiable = (Identifiable) obj;
Serializable id = identifiable.getId();
if(id != null) {
return id;
}
}
return super.generate(session, obj);
}
}
您可以将其映射到您的实体,如下所示:
@Id
@GenericGenerator(
name = "assigned-sequence",
strategy = "com.vladmihalcea.book.hpjp.hibernate.identifier.AssignedSequenceStyleGenerator",
parameters = @org.hibernate.annotations.Parameter(
name = "sequence_name",
value = "post_sequence"
)
)
@GeneratedValue(
generator = "assigned-sequence",
strategy = GenerationType.SEQUENCE
)
private Long id;
尝试这样的事情:
@Id
@Column( name = "ID" )
@TableGenerator(
name = "AppSeqStore",
table = "APP_SEQ_STORE",
pkColumnName = "APP_SEQ_NAME",
pkColumnValue = "LISTENER_PK",
valueColumnName = "APP_SEQ_VALUE",
initialValue = 1,
allocationSize = 1 )
@GeneratedValue( strategy = GenerationType.TABLE, generator = "AppSeqStore" )
而这个表在数据库中:
CREATE TABLE APP_SEQ_STORE (
APP_SEQ_NAME VARCHAR(255) NOT NULL,
APP_SEQ_VALUE NUMBER(10) NOT NULL,
PRIMARY KEY(APP_SEQ_NAME)
)
INSERT INTO APP_SEQ_STORE VALUES ('LISTENER_PK', 0)
这一切都适用于Oracle,MS Sql Server和使用JBoss作为App Server的MySql。
更多信息:
http://www.developerscrappad.com/408/java/java-ee/ejb3-jpa-3-ways-of-generating-primary-key-through-generatedvalue/