使用多个@GenericGenerator?

时间:2017-11-14 07:53:51

标签: java spring hibernate jpa

我在Spring Boot项目(Hibernate 5)中试验过Hibernate的@GenericGenerator。做了这样的测试实体:

@Entity
public class BatchTest implements Serializable {
    private static final long serialVersionUID = 3012542467060581674L;

    @Id
    @GeneratedValue(generator = "batchTestIdGenerator")
    @GenericGenerator(
            name = "batchTestIdGenerator",
            strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
            parameters = {
                    @org.hibernate.annotations.Parameter(name = "increment_size",value = "1000")
            }
    )
    private long id;

    @Lob
    @Column(nullable = false)
    private String someVal;
...

使用这个生成器我可以使用JPA快速插入实体(我有一个Spring存储库,由@Service提供)并且它很酷,但序列实际存储的是什么?我的数据库当前是一个SQL Server 2016实例,在模式中,我可以看到我有一个dbo.hibernate_sequenceenter image description here

如果我使用不同的生成器创建第二个实体,则在启动期间会出现异常:

@Id
@GeneratedValue(generator = "batchTestIdGenerator2", strategy = GenerationType.SEQUENCE)
@GenericGenerator(
        name = "batchTestIdGenerator2",
        strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
        parameters = {
                @org.hibernate.annotations.Parameter(name = "increment_size",value = "500")
        }
)
private long id;

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Multiple references to database sequence [hibernate_sequence] were encountered attempting toset conflicting values for 'increment size'.  Found [500] and [1000]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]

我可以定义不同的序列吗?看起来它试图对两个序列使用相同的dbo.hibernate_sequence(id没有在数据库中创建新的dbo序列)并且只是忽略了名称。如果可以定义N个序列号,我该怎么做?

编辑:我尝试手动创建序列(匹配名称),但我仍然得到相同的错误。

2 个答案:

答案 0 :(得分:1)

Hibernate允许您创建自己的序列生成器,允许您使用Hibernate IdentifierGenerator定义格式,表格所有内容。 请尝试以下方法。

通过实施SequenceGenerator创建IdentifierGenerator类,使用org.hibernate.id.Configurable界面使您的生成器可配置 - 将接受来自实体类的参数 -

自定义标识符生成器如下所示:

public class StringSequenceIdentifier 
        implements IdentifierGenerator, Configurable {

    public static final String SEQUENCE_PREFIX = "sequence_prefix";

    private String sequencePrefix;

    private String sequenceCallSyntax;

    @Override
    public void configure(
            Type type, Properties params, ServiceRegistry serviceRegistry)
            throws MappingException {
        final JdbcEnvironment jdbcEnvironment =
                serviceRegistry.getService(JdbcEnvironment.class);
        final Dialect dialect = jdbcEnvironment.getDialect();

        sequencePrefix = ConfigurationHelper.getString(
                SEQUENCE_PREFIX,
                params,
                "SEQ_");

        final String sequencePerEntitySuffix = ConfigurationHelper.getString(
                SequenceStyleGenerator.CONFIG_SEQUENCE_PER_ENTITY_SUFFIX,
                params,
                SequenceStyleGenerator.DEF_SEQUENCE_SUFFIX);

        final String defaultSequenceName = ConfigurationHelper.getBoolean(
                SequenceStyleGenerator.CONFIG_PREFER_SEQUENCE_PER_ENTITY,
                params,
                false)
                ? params.getProperty(JPA_ENTITY_NAME) + sequencePerEntitySuffix
                : SequenceStyleGenerator.DEF_SEQUENCE_NAME;

        sequenceCallSyntax = dialect.getSequenceNextValString(
                ConfigurationHelper.getString(
                        SequenceStyleGenerator.SEQUENCE_PARAM,
                        params,
                        defaultSequenceName));
    }

    @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;
            }
        }
        long seqValue = ((Number) Session.class.cast(session)
            .createSQLQuery(sequenceCallSyntax)
            .uniqueResult()).longValue();

        return sequencePrefix + String.format("%011d%s", 0 ,seqValue);
    }
}

实体将像

@Entity(name = "Post") @Table(name = "post")
public class Post implements Identifiable<String> {

    @Id
    @GenericGenerator(
        name = "assigned-sequence",
        strategy = "com.vladmihalcea.book.hpjp.hibernate.identifier.StringSequenceIdentifier",
        parameters = {
            @org.hibernate.annotations.Parameter(
                name = "sequence_name", value = "hibernate_sequence"),
            @org.hibernate.annotations.Parameter(
                name = "sequence_prefix", value = "CTC_"),
        }
    )
    @GeneratedValue(
        generator = "assigned-sequence", 
        strategy = GenerationType.SEQUENCE)
    private String id;

    @Version
    private Integer version;

    public Post() {
    }

    public Post(String id) {
        this.id = id;
    }

    @Override
    public String getId() {
        return id;
    }
}

有关详细说明,请参阅以下链接。 https://vladmihalcea.com/how-to-implement-a-custom-string-based-sequence-identifier-generator-with-hibernate/

答案 1 :(得分:0)

根据第11.1.48节JPA 2.1 specification

的SequenceGenerator注释

生成器名称的范围对于持久性单元是全局的(跨所有生成器类型)。

所以你不能有重复的发生器。