【发布时间】:2021-04-16 10:18:46
【问题描述】:
我们使用带有 Hibernate 5.4.8.Final 的 Spring Boot 2.2.1,方言 org.hibernate.dialect.Oracle12cDialect,针对带有 Open JDK 11 的 Oracle 19.3.0.0 数据库。
仅对某些开发人员而言,Hibernate 随机无法初始化并出现此异常:
org.hibernate.MappingException: The increment size of the [SEQ_THE_SEQUENCE] sequence is set to [10] in the entity mapping while the associated database sequence increment size is [1].
at org.hibernate.id.enhanced.SequenceStyleGenerator.configure(SequenceStyleGenerator.java:257)
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.createIdentifierGenerator(DefaultIdentifierGeneratorFactory.java:118)
... 42 common frames omitted
Wrapped by: org.hibernate.MappingException: Could not instantiate id generator [entity-name=com.[...].TheEntity]
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.createIdentifierGenerator(DefaultIdentifierGeneratorFactory.java:124)
at org.hibernate.mapping.SimpleValue.createIdentifierGenerator(SimpleValue.java:344)
at org.hibernate.internal.SessionFactoryImpl.lambda$new$1(SessionFactoryImpl.java:292)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1675)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:291)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1249)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:391)
... 25 common frames omitted
Wrapped by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not instantiate id generator [entity-name=com.[...].TheEntity]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:403)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:378)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1862)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1799)
... 21 common frames omitted
Wrapped by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not instantiate id generator [entity-name=com.[....]TheEntity]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1803)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1108)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at ....main(....java:28)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
序列由以下语句创建(我们使用的是flyway,所以在所有环境中都是一样的):
create sequence SEQ_THE_SEQUENCE
start with 1
increment by 10;
具有抽象父级的实体:
@MappedSuperclass
public abstract class AbstractParentEntity implements JpaBaseEntity {
public static final String SEQ_GENERATOR_NAME = "SEQ_GENERAL";
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_GENERATOR_NAME)
@Column(name = "[ID]", unique = true, nullable = false, insertable = false, updatable = false)
protected Long id;
...
}
@Entity
@Table(name = "[THE_ENTITY]")
@SequenceGenerator(name = AbstractParentEntity.SEQ_GENERATOR_NAME, sequenceName = "SEQ_THE_SEQUENCE", allocationSize = 10)
public class TheEntity extends AbstractParentEntity {
...
}
我们的应用使用的是Pooled Sequence generator,而不是hilo,它是在spring配置中配置的:
spring.jpa.properties.hibernate.id.new_generator_mappings: true
我知道https://hibernate.atlassian.net/browse/HHH-13783,但我认为它不适合我们的情况,因为它明确只会影响 hilo。
我已经对数据库中的序列进行了两次和三次检查,但它声明“以 10 为增量”,并且与在其中工作的所有其他环境中相同。我已经清理并重建了应用程序。我已经多次删除并重新创建了数据库并重新启动了 Oracle 数据库,因为我已经没有东西可以尝试了。我还能做些什么来解决这个问题?
编辑 1:
调试到SequenceStyleGenerator后,我可以解释这种行为。
这个 Hibernate 类中的方法getSequenceIncrementValue 尝试从数据库中读取增量值:
private Long getSequenceIncrementValue(JdbcEnvironment jdbcEnvironment, String sequenceName) {
return jdbcEnvironment.getExtractedDatabaseMetaData().getSequenceInformationList()
.stream()
.filter(
sequenceInformation -> {
Identifier catalog = sequenceInformation.getSequenceName().getCatalogName();
Identifier schema = sequenceInformation.getSequenceName().getSchemaName();
return sequenceName.equalsIgnoreCase( sequenceInformation.getSequenceName().getSequenceName().getText() ) &&
( catalog == null || catalog.equals( jdbcEnvironment.getCurrentCatalog() ) ) &&
( schema == null || schema.equals( jdbcEnvironment.getCurrentSchema() ) );
}
)
.map( SequenceInformation::getIncrementValue )
.filter( Objects::nonNull )
.findFirst()
.orElse( null );
}
...getSequenceInformationList() 的结果包含 两个 名为 SEQ_THE_SEQUENCE 的条目。一个来自应用程序模式,一个来自数据库中的另一个模式。该序列也存在那里,并且增量为 1。由于从 sequenceInformation 对象派生的变量 schema 对这两个条目都是空的,因此 Hibernate 处理第一个 - 那个,那是错误的架构。
现在的问题是,为什么缺少这个元数据。
【问题讨论】:
-
你使用什么hibernate方言?
-
org.hibernate.dialect.Oracle12cDialect,已将其添加到帖子中。