web-dev-qa-db-fra.com

Hibernate n'a pas pu récupérer les informations de séquence dans la base de données

J'ai récemment mis à jour hibernate dans mon application vers 5.4.4.Final. Et maintenant, j'ai rencontré l'exception suivante lors du déploiement.

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)

J'utilise le persistence.xml suivant.

<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>

Après une enquête plus approfondie, j'ai découvert que la cause première est la suivante: hibernate utilise l'interface SequenceInformation pour les manipulations de métadonnées de séquences

public interface SequenceInformation {
  Long getMinValue();
  Long getMaxValue();
  Long getIncrementValue();
  ...
}

Cependant, mon application utilise les séquences comme suit:

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

Le Long.MAX_VALUE est égal à 9223372036854775807, donc j'ai eu l'exception de dépassement numérique.

Alors, mes questions:

  • Est-ce un bug en hibernation?
  • Quelle sera la meilleure façon de le résoudre?

Maintenant, je vois les façons suivantes:

  1. Correction des déclarations de séquences. Cela peut être assez problématique dans mon cas. Et, en passant, il semble étrange que la mise en veille prolongée essaie de lire les métadonnées sur toutes les séquences, pas seulement sur celles utilisées dans mon application.
  2. Créez un dialecte personnalisé qui étendra Oracle12cDialect et remplacera getQuerySequencesString () et/ou getSequenceInformationExtractor ().
public class Oracle8iDialect extends Dialect {
  ...
  public String getQuerySequencesString() {
    return "select * from all_sequences";
  }

  public SequenceInformationExtractor getSequenceInformationExtractor() {
    return SequenceInformationExtractorOracleDatabaseImpl.INSTANCE;
  }
}

Je peux basculer SequenceInformationExtractor sur SequenceInformationExtractorNoOpImpl.INSTANCE et hibernate ne lira pas les séquences métadonnées. Quel impact cette décision aura-t-elle? Hibernate essaie de valider allocationSize de @SequenceGenerator () par INCREMENT_BY. Y a-t-il d'autres raisons?

Toute suggestion sera appréciée.

[~ # ~] mise à jour [~ # ~] : c'est HHH-13694

7
SternK

J'ai résolu le problème comme suit. Création d'une extension pour Oracle12cDialect. Limité la valeur maximale/minimale des colonnes à 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";
    }

}

Dans le fichier application.properties fait référence à une implémentation de dialecte

spring.jpa.properties.hibernate.dialect=ru.mvawork.hibernate.CustomOracleDialect

Vous pouvez recréer des séquences en limitant les valeurs minimales et maximales. Dans mon cas, je ne peux pas le faire. Les clés primaires que j'utilise ont le numéro de dimension (12), qui se situe dans la limite de plage de -9223372036854775807 à 9223372036854775808 avec une grande marge

0
Vasily Menshev