我在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_sequence
:
如果我使用不同的生成器创建第二个实体,则在启动期间会出现异常:
@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
个序列号,我该怎么做?
编辑:我尝试手动创建序列(匹配名称),但我仍然得到相同的错误。
答案 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)