GenerationType.AUTO
を使用した場合でも SEQUENCE固有のパラメーターがないと、割り当てられたIDを保存できません。
妥協する意思がある場合は、いくつかの回避策があります。
-
1つの方法は、割り当てられた識別子に切り替えることです。 MySQLとOracleの両方で機能するUUID識別子を使用でき、手動で値を割り当てることもできます。
-
別の方法は、カスタムテーブルジェネレータを使用することです。
まず、識別可能なインターフェースを定義します:
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;
すべてのコードはGitHubで入手でき、魅力のように機能します。