使用 org.hibernate.id.enhanced.SequenceStyleGenerator 实现。
SequenceStyleGenerator is capable of working against databases that do not support sequences by switching to a table as the underlying backing.
The preferred (and portable) way to configure this generator is using the JPA-defined javax.persistence.SequenceGenerator annotation.
Unnamed sequence
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;
public class Test {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
Person p = new Person();
em.getTransaction().begin();
em.persist(p);
em.getTransaction().commit();
em.close();
factory.close();
}
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
}
}
生成 SQL
drop table if exists Person cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Person (id int8 not null, primary key (id))
select nextval ('hibernate_sequence')
insert into Person (id) values (1)
Configured sequence
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;
import javax.persistence.SequenceGenerator;
public class Test {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
em.getTransaction().begin();
em.persist(p1);
em.persist(p2);
em.persist(p3);
em.getTransaction().commit();
em.close();
factory.close();
}
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq")
@SequenceGenerator(name = "my_seq", sequenceName = "my_sequence")
private Long id;
}
}
生成 SQL
drop table if exists Person cascade
drop sequence if exists my_sequence
create sequence my_sequence start 1 increment 50
create table Person (id int8 not null, primary key (id))
select nextval ('my_sequence')
select nextval ('my_sequence')
insert into Person (id) values (1)
insert into Person (id) values (2)
insert into Person (id) values (3)
注意
- 只有两次
select nextval ('my_sequence')
- SequenceGenerator 默认的 allocationSize 是 50 表示 pool 大小是 50 。但实际写入 Person 表中的 id 只是加一。
- 这个序列依次查询 nextval 得到的值应该是 1,51 。数据库中查看 my_sequence 的当前值是 51
参见 Optimizers
同一个 sequence 如果要在不同 Entity 中使用,需要在每个 Entity 中都定义一次!
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;
import javax.persistence.SequenceGenerator;
public class Test {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
Person p = new Person();
Address a = new Address();
em.getTransaction().begin();
em.persist(p);
em.persist(a);
em.getTransaction().commit();
em.close();
factory.close();
}
@Entity(name = "Person")
@SequenceGenerator(name = "my_seq", sequenceName = "my_sequence")
public static class Person {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq")
private Long id;
}
@Entity(name = "Address")
@SequenceGenerator(name = "my_seq", sequenceName = "my_sequence")
public static class Address {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq")
private Long id;
}
}
生成 SQL
drop table if exists Address cascade
drop table if exists Person cascade
drop sequence if exists my_sequence
create sequence my_sequence start 1 increment 50
create table Address (id int8 not null, primary key (id))
create table Person (id int8 not null, primary key (id))
select nextval ('my_sequence')
select nextval ('my_sequence')
select nextval ('my_sequence')
insert into Person (id) values (1)
insert into Address (id) values (52)
注意
- 有三次
select nextval ('my_sequence')
- 实际写入 Address 表中的 id 是 52 。这应该跟多 Tenant 有关
- 这个序列依次查询 nextval 得到的值应该是 1,51,101 。数据库中查看 my_sequence 的当前值是 101
参见 Optimizers
如果 Address 上不加 @SequenceGenerator 则抛异常 org.hibernate.AnnotationException: Unknown Id.generator: my_seq