2

Hibernate を持続性プロバイダーとして使用する WebSphere Liberty で単純な webapp を実行しています (WAR ファイルにライブラリーとして含まれています)。

アプリケーションが起動すると、Hibernate が初期化され、DB2 への接続が開かれ、いくつかの SQL ステートメントが発行されます。ただし、CICS で実行し、JDBC Type 2 Driver DataSource を使用すると、これは失敗します。次のメッセージがログに記録されます (読みやすいように改行が追加されています)。

WARN  org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator -
    HHH000342: Could not obtain connection to query metadata : [jcc][50053][12310][4.19.56]
    T2zOS exception: [jcc][T2zos]T2zosCicsApi.checkApiStatus:
       Thread is not CICS-DB2 compatible: CICS_REGION_BUT_API_DISALLOWED ERRORCODE=-4228, SQLSTATE=null
...
ERROR org.hibernate.hql.spi.id.IdTableHelper - Unable obtain JDBC Connection
com.ibm.db2.jcc.am.SqlException: [jcc][50053][12310][4.19.56] T2zOS exception: [jcc][T2zos]T2zosCicsApi.checkApiStatus:
       Thread is not CICS-DB2 compatible: CICS_REGION_BUT_API_DISALLOWED ERRORCODE=-4228, SQLSTATE=null
    at com.ibm.db2.jcc.am.kd.a(Unknown Source) ~[db2jcc4.jar:?]
    ...
    at com.ibm.db2.jcc.t2zos.T2zosConnection.a(Unknown Source) ~[db2jcc4.jar:?]
    ...
    at com.ibm.db2.jcc.DB2SimpleDataSource.getConnection(Unknown Source) ~[db2jcc4.jar:?]
    at com.ibm.cics.wlp.jdbc.internal.CICSDataSource.getConnection(CICSDataSource.java:176) ~[?:?]
    at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) ~[our-app.war:5.1.0.Final]
    at org.hibernate.internal.SessionFactoryImpl$3.obtainConnection(SessionFactoryImpl.java:643) ~[our-app.war:5.1.0.Final]
    at org.hibernate.hql.spi.id.IdTableHelper.executeIdTableCreationStatements(IdTableHelper.java:67) [our-app.war:5.1.0.Final]
    at org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy.finishPreparation(GlobalTemporaryTableBulkIdStrategy.java:125) [our-app.war:5.1.0.Final]
    at org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy.finishPreparation(GlobalTemporaryTableBulkIdStrategy.java:42) [our-app.war:5.1.0.Final]
    at org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl.prepare(AbstractMultiTableBulkIdStrategyImpl.java:88) [our-app.war:5.1.0.Final]
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:451) [our-app.war:5.1.0.Final]

私の現在の理解では、CICS で実行し、JDBC Type 2 ドライバーを使用する場合、一部のスレッドのみが DB2 接続を開くことができます。それは、アプリケーション スレッド (HTTP 要求を処理するスレッド) と、サービスを提供するワーカー スレッドCICSExecutorServiceです。

現在の解決策は次のとおりです。

  1. プロパティを に JdbcEnvironmentInitiator設定して、JDBC メタデータ ルックアップを無効にします。hibernate.temp.use_jdbc_metadata_defaultsfalse
  2. の実行を にラップIdTableHelper#executeIdTableCreationStatementsし、Runnableに送信しCICSExecutorServiceます。

このソリューションは、本番環境に十分かつ適していると思いますか? それとも、別のアプローチを使用していますか?

使用したバージョン:

  • z/OS 5.3.0 用の CICS トランザクション サーバー
  • WebSphere アプリケーション サーバー 8.5.5.8
  • 休止状態 5.1.0

更新:明確にするために、アプリケーションが開始されると、問題なく DB2 を照会できます (HTTP 要求を処理する場合)。問題は起動にのみ関連しています。

4

2 に答える 2

0

Liberty の JPA 機能に対する CICS TS v5.3 サポートは、最近のサービス更新 (2016 年 7 月) で利用可能になりました。その更新の前に、アプリケーションで JPA を実行しようとすると、説明したものと非常によく似た問題が発生します。

hibernate を実行していて、CICS 対応のスレッドを使用していますが、API 環境がありません (タイプ 2 JDBC 呼び出しを成功させることができます)。新しい検出ロジックは、DB2 JDBC タイプ 2 ドライバーおよび JPA で使用するために (排他的ではありませんが) 特別に開発されました。このアップデートは最近のサービス更新で出荷され、発生している問題を解決する可能性があります。

適用してみてください: http://www-01.ibm.com/support/docview.wss?crawler=1&uid=swg1PI58375

説明には、「標準モードの Liberty」サポート用であると書かれていますが、上記で概説した他の開発が含まれています。

于 2016-09-16T12:35:37.913 に答える
0

次のソリューションは、問題なく動作することがテストされています。

アイデアは、を使用して SQL/DDL ステートメントを実行することCICSExecutorService#runAsCICSです。次の拡張子は、hibernate.hql.bulk_id_strategyプロパティを介して登録されます。

package org.hibernate.hql.spi.id.global;

import java.util.concurrent.*;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.springframework.util.ClassUtils;
import com.ibm.cics.server.*;

public class CicsAwareGlobalTemporaryTableBulkIdStrategy extends GlobalTemporaryTableBulkIdStrategy {

    @Override
    protected void finishPreparation(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess, MetadataImplementor metadata, PreparationContextImpl context) {
        execute(() -> super.finishPreparation(jdbcServices, connectionAccess, metadata, context));
    }

    @Override
    public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess) {
        execute(() -> super.release(jdbcServices, connectionAccess));
    }

    private void execute(Runnable runnable) {
        if (isCics() && IsCICS.getApiStatus() == IsCICS.CICS_REGION_BUT_API_DISALLOWED) {
            RunnableFuture<Void> task = new FutureTask<>(runnable, null);
            CICSExecutorService.runAsCICS(task);
            try {
                task.get();
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException("Failed to execute in a CICS API-enabled thread. " + e.getMessage(), e);
            }
        } else {
            runnable.run();
        }
    }

    private boolean isCics() {
        return ClassUtils.isPresent("com.ibm.cics.server.CICSExecutorService", null);
    }
}

新しい JCICS API バージョンには、 をrunAsCics受け入れるメソッドのオーバーロードがあることに注意してください。これは、メソッドの CICS ブランチを次のようCallableに単純化するのに役立つ場合があります。execute

CICSExecutorService.runAsCICS(() -> { runnable.run(); return null; }).get();

いくつかの代替案を試しました:

  1. 接続取得アクション ( org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl#getConnection) だけをラップしても、メイン スレッドで使用されたときに接続が既に閉じられているため、機能しませんでした。
  2. アプリケーションの起動全体 ( org.springframework.web.context.ContextLoaderListener#contextInitialized) をラップすると、クラスローディングの問題が発生しました。

編集:MultiTableBulkIdStrategy最終的には、起動時に SQL/DDL を実行しないカスタム Hibernate の実装を採用しました ( GitHub のプロジェクト ページを参照)。

于 2016-09-19T07:44:09.180 に答える