Ste*_*rnK 17 java oracle spring hibernate
我最近将我的应用程序中的 hibernate 更新为 5.4.4.Final。现在,我在部署过程中遇到了以下异常。
ERROR [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl|[STANDBY] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)']
Could not fetch the SequenceInformation from the database
java.sql.SQLException: Numeric Overflow
at oracle.jdbc.driver.NumberCommonAccessor.throwOverflow(NumberCommonAccessor.java:4136)
at oracle.jdbc.driver.NumberCommonAccessor.getLong(NumberCommonAccessor.java:634)
at oracle.jdbc.driver.GeneratedStatement.getLong(GeneratedStatement.java:206)
at oracle.jdbc.driver.GeneratedScrollableResultSet.getLong(GeneratedScrollableResultSet.java:259)
at oracle.jdbc.driver.GeneratedResultSet.getLong(GeneratedResultSet.java:558)
at weblogic.jdbc.wrapper.ResultSet_oracle_jdbc_driver_ForwardOnlyResultSet.getLong(Unknown Source)
at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.resultSetMaxValue(SequenceInformationExtractorLegacyImpl.java:139)
at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.extractMetadata(SequenceInformationExtractorLegacyImpl.java:61)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl.sequenceInformationList(JdbcEnvironmentImpl.java:403)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl.<init>(JdbcEnvironmentImpl.java:268)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:114)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:175)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:118)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:900)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:931)
at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:141)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:956)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:747)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at com.sternkn.app.services.web.AppContextLoaderListener.<clinit>(AppContextLoaderListener.java:30)
Run Code Online (Sandbox Code Playgroud)
我使用以下persistence.xml。
ERROR [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl|[STANDBY] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)']
Could not fetch the SequenceInformation from the database
java.sql.SQLException: Numeric Overflow
at oracle.jdbc.driver.NumberCommonAccessor.throwOverflow(NumberCommonAccessor.java:4136)
at oracle.jdbc.driver.NumberCommonAccessor.getLong(NumberCommonAccessor.java:634)
at oracle.jdbc.driver.GeneratedStatement.getLong(GeneratedStatement.java:206)
at oracle.jdbc.driver.GeneratedScrollableResultSet.getLong(GeneratedScrollableResultSet.java:259)
at oracle.jdbc.driver.GeneratedResultSet.getLong(GeneratedResultSet.java:558)
at weblogic.jdbc.wrapper.ResultSet_oracle_jdbc_driver_ForwardOnlyResultSet.getLong(Unknown Source)
at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.resultSetMaxValue(SequenceInformationExtractorLegacyImpl.java:139)
at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.extractMetadata(SequenceInformationExtractorLegacyImpl.java:61)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl.sequenceInformationList(JdbcEnvironmentImpl.java:403)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl.<init>(JdbcEnvironmentImpl.java:268)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:114)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:175)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:118)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:900)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:931)
at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:141)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:956)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:747)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at com.sternkn.app.services.web.AppContextLoaderListener.<clinit>(AppContextLoaderListener.java:30)
Run Code Online (Sandbox Code Playgroud)
经过进一步调查,我发现根本原因如下:hibernate 使用SequenceInformation接口进行序列元数据操作
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
version="2.2">
<persistence-unit name="appPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle12cDialect" />
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value = "true"/>
<property name="hibernate.cache.use_query_cache" value="false" />
<property name="hibernate.cache.region.factory_class" value="ehcache"/>
<property name="hibernate.cache.ehcache.missing_cache_strategy" value="create" />
<property name="hibernate.cache.region_prefix" value="app_cache" />
<property name="net.sf.ehcache.configurationResourceName" value="/META-INF/app-ehcache.xml" />
<property name="hibernate.bytecode.provider" value="bytebuddy" />
</properties>
</persistence-unit>
</persistence>
Run Code Online (Sandbox Code Playgroud)
但是,我的应用程序使用如下序列:
SQL> CREATE SEQUENCE SEQ_TEST START WITH 1 INCREMENT BY 1 NOCYCLE;
SQL> select MIN_VALUE, MAX_VALUE, INCREMENT_BY
from USER_SEQUENCES
where SEQUENCE_NAME = 'SEQ_TEST';
MIN_VALUE MAX_VALUE INCREMENT_BY
--------- ---------------------------- ------------
1 9999999999999999999999999999 1
Run Code Online (Sandbox Code Playgroud)
该Long.MAX_VALUE等于9223372036854775807,所以我得到的数字溢出异常。
所以,我的问题:
现在我看到以下方法:
public interface SequenceInformation {
Long getMinValue();
Long getMaxValue();
Long getIncrementValue();
...
}
Run Code Online (Sandbox Code Playgroud)
我可以将SequenceInformationExtractor切换到SequenceInformationExtractorNoOpImpl.INSTANCE并且休眠不会读取序列元数据。这个决定会产生什么影响?Hibernate 尝试通过 INCREMENT_BY来验证@SequenceGenerator() 的allocationSize。还有其他原因吗?
任何建议将不胜感激。
更新:这是HHH-13694
小智 10
我解决了以下问题。为 Oracle12cDialect 创建了一个扩展。将列的最大值/最小值限制为 SQL
package ru.mvawork.hibernate;
import org.hibernate.dialect.Oracle12cDialect;
@SuppressWarnings("unused")
public class CustomOracleDialect extends Oracle12cDialect {
@Override
public String getQuerySequencesString() {
return "select SEQUENCE_OWNER, SEQUENCE_NAME, greatest(MIN_VALUE, -9223372036854775807) MIN_VALUE,\n"+
"Least(MAX_VALUE, 9223372036854775808) MAX_VALUE, INCREMENT_BY, CYCLE_FLAG, ORDER_FLAG, CACHE_SIZE,\n"+
"Least(greatest(LAST_NUMBER, -9223372036854775807), 9223372036854775808) LAST_NUMBER,\n"+
"PARTITION_COUNT, SESSION_FLAG, KEEP_VALUE\n"+
"from all_sequences";
}
}
Run Code Online (Sandbox Code Playgroud)
在 application.properties 文件中引用了方言实现
spring.jpa.properties.hibernate.dialect=ru.mvawork.hibernate.CustomOracleDialect
Run Code Online (Sandbox Code Playgroud)
您可以通过限制最小值和最大值来重新创建序列。就我而言,我做不到。我使用的主键有维度 Number (12),它在 -9223372036854775807 到 9223372036854775808 的范围限制内,有很大的余量
最后,我想出了以下解决方案:
SequenceInformationExtractorOracleDatabaseImpl:public class AppSequenceInformationExtractor extends SequenceInformationExtractorOracleDatabaseImpl
{
/**
* Singleton access
*/
public static final AppSequenceInformationExtractor INSTANCE = new AppSequenceInformationExtractor();
@Override
protected Long resultSetMinValue(ResultSet resultSet) throws SQLException {
return resultSet.getBigDecimal("min_value").longValue();
}
}
Run Code Online (Sandbox Code Playgroud)
是的,我知道我们可能会丢失有关此BigDecimal值的整体大小和精度的信息,并返回具有相反符号的结果。但是,这并不重要,因为这史蒂夫埃伯索尔的有关意见Long getMinValue(),并Long getMaxValue()从方法SequenceInformation接口:
我实际上很想从
SequenceInformation. 我们从不以任何有意义的方式使用它们。或者将这 2 个方法的返回类型从Longto更改为BigInteger- 可以BigDecimal改为,但该值隐式为整数(在整数意义上)。我想在这一点上,在游戏中做这些都为时已晚,所以像你的改变这样的事情很好 - 就像我说的,我们永远不会使用这些值。我们绝对应该弃用这两种方法 IMO。
所以,这个技巧只允许用最少的额外编码来避免异常。
Oracle12cDialect:public class AppOracleDialect extends Oracle12cDialect
{
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return AppSequenceInformationExtractor.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return "select * from user_sequences";
}
}
Run Code Online (Sandbox Code Playgroud)
persistence.xml:<property name="hibernate.dialect" value="com.my.app.AppOracleDialect" />
Run Code Online (Sandbox Code Playgroud)
至于getQuerySequencesString()覆盖和使用的方法USER_SEQUENCES而不是ALL_SEQUENCES有争议的(参见HHH-13322和HHH-14022)。但是,就我而言,USER_SEQUENCES使用更可取。
您简单地使用了序列的 dafault MAX_VALUE,这对于 Java LONG 数据类型来说太高了。
幸运的是,您可以随时MAX_VALUE使用 ALTER SEQUENCE将ALTER SEQUENCE重置为较低的数字,这不会导致任何问题。
例子
CREATE SEQUENCE SEQ_TEST START WITH 1 INCREMENT BY 1 NOCYCLE;
select MAX_VALUE from ALL_SEQUENCES where SEQUENCE_NAME = 'SEQ_TEST';
MAX_VALUE
----------
9999999999999999999999999999
ALTER SEQUENCE SEQ_TEST
MAXVALUE 9223372036854775807;
select MAX_VALUE from ALL_SEQUENCES where SEQUENCE_NAME = 'SEQ_TEST';
MAX_VALUE
----------
9223372036854775807
Run Code Online (Sandbox Code Playgroud)
顺便说一句
hibernate 尝试读取有关所有序列的元数据,而不仅仅是在我的应用程序中使用的元数据,这看起来很奇怪。
Hibernateselect * from all_sequences用作 Oracle Dialect 来获取序列信息。请注意,ALL_SEQUENCES这并不意味着所有现有序列,而是所有序列,您的 Hibernate 数据库用户(连接池中的 DBUSER)被授予使用权 -这当然是绝对正确的。
| 归档时间: |
|
| 查看次数: |
21230 次 |
| 最近记录: |