1. ホーム
  2. java

[解決済み] HibernateはデータベースからSequenceInformationをフェッチできませんでした。

2022-02-06 10:51:53

質問

最近、私のアプリケーションの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)

私は以下の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>

さらに調査した結果、根本的な原因は以下の通りであることがわかりました。 SequenceInformation インターフェイスを使用して、シーケンスのメタデータを操作します。

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

ロング.MAX_VALUE は 9223372036854775807 に等しいので、数値のオーバーフロー例外が発生しました。

では、質問です。

  • hibernateのバグでしょうか?
  • 解決するにはどうしたらよいでしょうか?

今、私は次のような方法を考えています。

  1. 配列の宣言を修正する。 私の場合、かなり問題がある可能性があります。また、私のアプリケーションで使用されているシーケンスだけでなく、すべてのシーケンスに関するメタデータを読み取ろうとするのは、奇妙に見えます。
  2. Oracle12cDialectを拡張し、getQuerySequencesString()やgetSequenceInformationExtractor()をオーバーライドするカスタム方言を作成する。
public class Oracle8iDialect extends Dialect {
  ...
  public String getQuerySequencesString() {
    return "select * from all_sequences";
  }

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

切り替えることができる SequenceInformationExtractor から SequenceInformationExtractorNoOpImpl.INSTANCE(シーケンスインフォメーションエクストラクターノープリップインプラント)。 となり、hibernate はシーケンスのメタデータを読み込まなくなります。この決定はどのような影響を与えるのでしょうか。Hibernate は以下を検証しようとします。 アロケーションサイズ の @SequenceGenerator() の INCREMENT_BY によるものである。他の理由はありますか?

何かご指摘があれば、よろしくお願いします。

アップデイト : これは HHH-13694

解決方法は?

結局、次のような解決策を思いつきました。

  1. を拡張した配列情報抽出器を作成します。 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 の値だけでなく、逆の符号の結果も返します。しかし、これは、以下の理由により重要ではありません。 これ Steve Ebersoleのコメントで Long getMinValue()Long getMaxValue() メソッドから SequenceInformation インターフェイスを使用します。

実は、この2つのメソッドを SequenceInformation . 私たちは、これらを有意義に使うことはありません。 あるいは、この2つのメソッドの戻り値の型を Long から BigInteger - である可能性があります。 BigDecimal しかし、この値は暗黙のうちに整数である。

この時点では、これらのいずれかを行うには遅すぎると思いますので、あなたの変更のようなもので良いと思います。 この2つのメソッドは絶対に非推奨にすべきですIMO。

つまり、このトリックは、最小限の厄介な追加コーディングで例外を回避することを可能にするだけなのです。

  1. を拡張するハイバーネート弁を作成します。 Oracle12cDialect :
public class AppOracleDialect extends Oracle12cDialect
{
   @Override
   public SequenceInformationExtractor getSequenceInformationExtractor() {
      return AppSequenceInformationExtractor.INSTANCE;
   }
   
   @Override
   public String getQuerySequencesString() {
      return "select * from user_sequences";
   }
}

  1. そして、この方言を persistence.xml :
<property name="hibernate.dialect" value="com.my.app.AppOracleDialect" />

メソッドについては getQuerySequencesString() オーバーライドと使用法 USER_SEQUENCES の代わりに ALL_SEQUENCES というのは議論の余地があります(参照 HHH-13322 HHH-14022 ). しかし、私の場合は USER_SEQUENCES の使い方が望ましいと思います。