Ngay cả khi bạn đã sử dụng GenerationType.AUTO
nếu không có bất kỳ thông số SEQUENCE cụ thể nào, bạn sẽ không thể lưu các số nhận dạng được chỉ định.
Có một số cách giải quyết nếu bạn sẵn sàng thực hiện một số thỏa hiệp:
-
Một cách sẽ là chuyển sang các số nhận dạng được chỉ định. Bạn có thể sử dụng mã định danh UUID, hoạt động cho cả MySQL và Oracle và bạn cũng có thể gán giá trị theo cách thủ công.
-
Một cách khác là sử dụng trình tạo bảng tùy chỉnh.
Đầu tiên, bạn xác định một giao diện có thể nhận dạng:
public interface Identifiable<T extends Serializable> {
T getId();
}
Sau đó, bạn mở rộng trình tạo bảng:
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);
}
}
Trình tạo này có thể kết hợp các số nhận dạng được chỉ định với các số nhận dạng được tạo tổng hợp:
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();
});
tạo các câu lệnh sau:
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)
Đối với Oracle, bạn có thể kết hợp SEQUENCE và các trình tạo được chỉ định. Tóm lại, hãy xem xét trình tạo sau:
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);
}
}
Bạn có thể ánh xạ nó tới các thực thể của mình như sau:
@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;
Tất cả mã đều có sẵn trên GitHub và hoạt động như một sự quyến rũ.