使用 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

results matching ""

    No results matching ""