简体   繁体   English

使用 PostgreSQL 的一个实体的多个 Hibernate 序列生成器

[英]Multiple Hibernate sequence generators for one entity with PostgreSQL

Can I use Multiple sequence generators for one entity, like我可以为一个实体使用多个序列生成器吗,比如

@Id
@SequenceGenerator(name=”subscription_id_seq”,sequenceName=”subscription_id_seq”, allocationSize=7)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator=”subscription_id_seq”)
@Column(unique=true, nullable=false)
private Integer id

@Column(name="code", nullable=false, unique=true )
@SequenceGenerator(name="subscription_code_1_seq",sequenceName="subscription_code_1_seq", allocationSize=7)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="subscription_code_1_seq")
private Integer code;

No you can not. 你不能。 The generator are applicable for identifier columns only. 生成器仅适用于标识符列。

Make sure you create this sequence with a script (eg hibernate.hbm2ddl.import_files ): 确保使用脚本创建此序列(例如hibernate.hbm2ddl.import_files ):

create sequence subscription_code_1_seq start 1 increment 7

Then use a mapping like this: 然后使用这样的映射:

@Id
@SequenceGenerator(
        name="subscription_id_seq",
        sequenceName="subscription_id_seq",
        allocationSize=7
)
@GeneratedValue(
        strategy=GenerationType.SEQUENCE,
        generator="subscription_id_seq"
)
@Column(unique=true, nullable=false)
private Integer id;

@Column(
        name="code",
        nullable=false,
        unique=true,
        insertable = false,
        updatable = false,
        columnDefinition = "BIGINT DEFAULT nextval('subscription_code_1_seq')"
)
@Generated(GenerationTime.INSERT)
private Integer code;

In nutshell, you can use multiple sequence generators for one entity but for primary keys only (composite primary key). 简而言之,您可以为一个实体使用多个序列生成器,但仅对主键使用 (复合主键)。

From SequenceGenerator documentation: 来自SequenceGenerator文档:

Defines a primary key generator that may be referenced by name when a generator element is specified for the GeneratedValue annotation. 定义在为GeneratedValue批注指定生成元素时可以通过名称引用的主键生成器。 A sequence generator may be specified on the entity class or on the primary key field or property. 可以在实体类或主键字段或属性上指定序列生成器。 The scope of the generator name is global to the persistence unit (across all generator types). 生成器名称的范围对于持久性单元是全局的(跨所有生成器类型)。

Code example: 代码示例:

public class TestPK implements Serializable {

    private Integer test1;

    private Integer test2;

    ...
}

@Entity
@IdClass(TestPK.class)
public class Test implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @SequenceGenerator(name = "seq_test1", sequenceName = "seq_test1", allocationSize = 7)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_test1")
    @Column(name = "test1", unique = true, nullable = false)
    private Integer test1;

    @Id
    @Column(name = "test2", nullable = false, unique = true)
    @SequenceGenerator(name = "seq_test2", sequenceName = "seq_test2", allocationSize = 7)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_test2")
    private Integer test2;

    ...

    @Override
    public String toString() {
        return "Test{" +
                "test1=" + test1 +
                ", test2=" + test2 +
                '}';
    }
}

public interface TestRepository extends Repository<Test, String> {

    Page<Test> findAll(Pageable pageable);

    void save(Test test);
}

@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired
    private TestRepository testRepository;

    @Override
    public void run(String... args) throws Exception {
        testRepository.save(new Test());
        Page<Test> all = testRepository.findAll(null);
        System.out.println(all.iterator().next());
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

An alternative solution would be to use @GeneratorType.另一种解决方案是使用@GeneratorType。 With this annotation, you can provide a custom implementation during insert and update of the hosting entity.使用此注释,您可以在托管实体的插入和更新期间提供自定义实现。 In this case, adding a sequence在这种情况下,添加一个序列

First create this sequence and add it during the creation or altering of the table:首先创建此序列并在创建或更改表期间添加它:

CREATE SEQUENCE project_code_seq INCREMENT 1 START 1;
ALTER TABLE project
    ADD COLUMN key bigint NOT NULL DEFAULT nextval('project_code_seq');

Create a class that implements the ValueGenerator:创建一个实现 ValueGenerator 的类:

public class ProjectCodeGenerator implements ValueGenerator<Long> {

    private static final String SELECT_NEXTVAL = "select nextval('project_code_seq')";

    @Override
    public Long generateValue(Session session, Object object) {
        if (object instanceof ProjectEntity project) {

                var result = (BigInteger) session.createNativeQuery(SELECT_NEXTVAL)
                        .setHibernateFlushMode(
                                FlushMode.COMMIT).getSingleResult();
                return result.longValue();
                
        } else {
            throw new RuntimeException("Can only be used for " + ProjectEntity.class);
        }
    }

}

Then on the entity you can add the @GeneratorType annotation:然后在实体上可以添加 @GeneratorType 注释:

@GeneratorType(type = ProjectCodeGenerator.class, when = GenerationTime.INSERT)
private Long code;

Note that the ProjectCodeGenerator can be tuned to whatever you desire and more logic can be added.请注意,ProjectCodeGenerator 可以根据您的需要进行调整,并且可以添加更多逻辑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM