최대 절전 모드에서 데이터베이스에서 시퀀스 정보를 가져올 수 없습니다.
최근에 응용 프로그램에서 최대 절전 모드를 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)
다음 persistence.xml을 사용합니다.
<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>
추가 조사 후, 저는 근본 원인이 다음과 같다는 것을 발견했습니다: 최대 절전 모드는 시퀀스 메타데이터 조작을 위해 시퀀스 정보 인터페이스를 사용합니다.
public interface SequenceInformation {
Long getMinValue();
Long getMaxValue();
Long getIncrementValue();
...
}
그러나 내 앱은 다음과 같은 시퀀스를 사용합니다.
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
Long.MAX_VALUE는 922372036854775807과 같으므로 숫자 오버플로 예외가 발생했습니다.
자, 제 질문은 다음과 같습니다.
- 겨울잠을 자는 벌레인가요?
- 그것을 해결하는 가장 좋은 방법은 무엇일까요?
이제 다음과 같은 방법을 알게 되었습니다.
- 시퀀스 선언을 수정합니다.제 경우에는 상당히 문제가 될 수 있습니다.그런데, 휴면기가 제 애플리케이션에서 사용되는 것뿐만 아니라 모든 시퀀스에 대한 메타데이터를 읽으려고 하는 것이 이상하게 보입니다.
- Oracle12cDialect를 확장하고 getQuerySequencesString() 및/또는 getSequenceInformation을 재정의하는 사용자 지정 사투리 만들기추출기().
public class Oracle8iDialect extends Dialect {
...
public String getQuerySequencesString() {
return "select * from all_sequences";
}
public SequenceInformationExtractor getSequenceInformationExtractor() {
return SequenceInformationExtractorOracleDatabaseImpl.INSTANCE;
}
}
시퀀스 정보를 전환할 수 있습니다.추출기에서 시퀀스 정보로ExtractorNoOpImppl.인스턴스 및 최대 절전 모드에서는 시퀀스 메타데이터를 읽지 않습니다.이 결정이 어떤 영향을 미칠까요?최대 절전 모드는 INCREMENT_BY를 통해 @SequenceGenerator()의 allocationSize를 검증하려고 합니다.다른 이유가 있습니까?
어떤 제안이든 감사하겠습니다.
업데이트: HHH-13694입니다.
저는 다음과 같이 문제를 해결했습니다.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";
}
}
application.properties 파일에서 사투리 구현을 참조했습니다.
spring.jpa.properties.hibernate.dialect=ru.mvawork.hibernate.CustomOracleDialect
최소값과 최대값을 제한하여 시퀀스를 재생성할 수 있습니다.저 같은 경우에는 할 수 없습니다.제가 사용하는 기본 키의 치수 번호(12)는 -922372036854775807에서 922372036854775808까지의 범위 내에 있으며 마진이 큽니다.
결국, 저는 다음과 같은 해결책을 생각해냈습니다.
- 확할시퀀정추만들기출기보를 확장하는 시퀀스 .
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(super.sequenceMinValueColumn()).longValue();
}
}
네, 저는 우리가 이것의 전체적인 규모와 정확성에 대한 정보를 잃을 수 있다는 것을 이해합니다.BigDecimal
값을 지정하고 반대 기호를 사용하여 결과를 반환합니다.하지만 이것은 스티브 에버솔의 언급 때문에 중요하지 않습니다.Long getMinValue()
그리고.Long getMaxValue()
의드소의 SequenceInformation
인터페이스:
저는 실제로 이 두 가지 방법을 에서 삭제하고 싶습니다. 우리는 결코 그것들을 의미 있는 방식으로 사용하지 않습니다.또는 이 두 가지 방법에 대한 반환 유형을 다음에서 변경합니다.
Long
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";
}
}
- 그리고 이 방언을 사용합니다.
persistence.xml
:
<property name="hibernate.dialect" value="com.my.app.AppOracleDialect" />
는 법은방.getQuerySequencesString()
의 및 선우 및법용USER_SEQUENCES
에 ALL_SEQUENCES
논쟁의 여지가 있습니다(HHH-13322 및 HHH-14022 참조).하지만, 제 경우에는,USER_SEQUENCES
사용하는 것이 좋습니다.
Java LONG 데이터 유형에 비해 너무 높은 시퀀스의 dafault MAX_VALUE를 사용했습니다.
다행스럽게도 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
및 BTW
최대 절전 모드가 내 응용 프로그램에서 사용되는 것뿐만 아니라 모든 시퀀스에 대한 메타데이터를 읽으려고 하는 것이 이상하게 보입니다.
는 최대절모사용을 사용합니다.select * from all_sequences
시퀀스 정보를 가져오는 Oracle 방언입니다.:ALL_SEQUENCES
모든 기존 시퀀스가 아니라 Hibernate 데이터베이스 사용자(연결 풀의 DBUSER)에게 사용 권한이 부여된 모든 시퀀스를 의미합니다. 물론 이는 절대적으로 정확합니다.
아래와 같은 방언 속성을 "application.properties"에 추가(또는 변경)합니다.
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
저는 @sternk가 제안한 것과 이미 최대 절전 모드 저장소에 풀 요청으로 존재하지만 아직 병합되지 않은 것의 하이브리드 솔루션을 제안하고자 합니다.
여기서 허용된 답은 빅 십진수가 long으로 변환되면 값의 부호를 변경합니다.
승인된 답변이 작동하지 않는지 확인하기 위해 다음과 같은 간단한 단위 검정을 실행할 수 있습니다.
@Test
public void testSignChange() {
final BigDecimal minValue = BigDecimal.valueOf(Long.MIN_VALUE);
final BigDecimal minValueMinusTen = minValue.subtract(BigDecimal.TEN);
final long minValueMinusTenLong = minValueMinusTen.longValue();
System.out.println("Min value as big decimal: " + minValueMinusTen);
System.out.println("Min value as long: " + minValueMinusTenLong);
final BigDecimal maxValue = BigDecimal.valueOf(Long.MAX_VALUE);
final BigDecimal maxValuePlusTen = maxValue.add(BigDecimal.TEN);
final long maxValuePlusTenLong = maxValuePlusTen.longValue();
System.out.println("Max value as big decimal: " + maxValuePlusTen);
System.out.println("Max value as long: " + maxValuePlusTenLong);
}
그러면 출력이 다음과 같이 표시됩니다.
Min value as big decimal: -9223372036854775818
Min value as long: 9223372036854775798
Max value as big decimal: 9223372036854775817
Max value as long: -9223372036854775799
따라서 다음과 같이 최소값과 최대값을 모두 처리할 수 있는 솔루션을 제안하고자 합니다.
public class SequenceInformationExtractor extends SequenceInformationExtractorOracleDatabaseImpl {
public static final SequenceInformationExtractor INSTANCE = new SequenceInformationExtractor();
private static final BigDecimal LONG_MIN_VALUE_AS_DECIMAL = BigDecimal.valueOf(Long.MIN_VALUE);
private static final BigDecimal LONG_MAX_VALUE_AS_DECIMAL = BigDecimal.valueOf(Long.MAX_VALUE);
@Override
protected String sequenceMaxValueColumn() {
return "max_value";
}
@Override
public Long resultSetMinValue(final ResultSet resultSet) throws SQLException {
final BigDecimal asDecimal = resultSet.getBigDecimal(this.sequenceMinValueColumn());
if (asDecimal.compareTo(SequenceInformationExtractor.LONG_MIN_VALUE_AS_DECIMAL) < 0) {
return Long.MIN_VALUE;
}
return asDecimal.longValue();
}
@Override
public Long resultSetMaxValue(final ResultSet resultSet) throws SQLException {
final BigDecimal asDecimal = resultSet.getBigDecimal(this.sequenceMaxValueColumn());
if (asDecimal.compareTo(SequenceInformationExtractor.LONG_MAX_VALUE_AS_DECIMAL) > 0) {
return Long.MAX_VALUE;
}
return asDecimal.longValue();
}
}
Postgre용SQL, 나는 Hibernate가 이 문제를 해결할 때까지 이 클래스를 방언으로 사용했습니다.
package com.societe.dialect;
import org.hibernate.dialect.PostgreSQL95Dialect;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
public class PostgresqlCustomDialect extends PostgreSQL95Dialect {
public String getQuerySequencesString() {
return "select * from all_sequences";
}
public SequenceInformationExtractor getSequenceInformationExtractor() {
return SequenceInformationExtractorNoOpImpl.INSTANCE;
}
}
언급URL : https://stackoverflow.com/questions/58570032/hibernate-could-not-fetch-the-sequenceinformation-from-the-database
'IT' 카테고리의 다른 글
사용자의 터치로 완벽한 원 그리기 (0) | 2023.07.02 |
---|---|
MySQL의 TEXT 유형에 해당하는 Oracle (0) | 2023.07.02 |
vuex 스토어의 라우터 ID에 액세스하고 Axios get 메서드에 추가하려면 어떻게 해야 합니까? (0) | 2023.07.02 |
Hg: git's rebase와 같은 rebase를 하는 방법 (0) | 2023.07.02 |
C 표준 보증 버퍼는 Null 터미네이터를 지나치지 않습니까? (0) | 2023.07.02 |