Hibernate подключается к DB2 при запуске приложения в WAS Liberty на CICS
Мы запускаем простое веб-приложение на WebSphere Liberty, которое использует Hibernate в качестве поставщика постоянных данных (включен в качестве библиотеки в файле WAR).
Когда приложение запускается, Hibernate инициализируется, и он открывает соединение с DB2 и выдает некоторые операторы SQL. Однако это не работает при работе в CICS и использовании источника данных драйвера JDBC типа 2. Следующие сообщения регистрируются (некоторые дополнительные разрывы строк для удобства чтения):
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 типа 2 только некоторые потоки могут открывать соединение DB2. Это были бы потоки приложений (те, которые обрабатывают запросы HTTP), а также обслуживание рабочих потоков. CICSExecutorService
,
Текущее решение:
- Отключить поиск метаданных JDBC в
JdbcEnvironmentInitiator
установивhibernate.temp.use_jdbc_metadata_defaults
собственность наfalse
- Завершение исполнения
IdTableHelper#executeIdTableCreationStatements
вRunnable
и отправить егоCICSExecutorService
,
Считаете ли вы это решение достаточным и пригодным для производства? Или, может быть, вы используете другой подход?
Используемые версии:
- Сервер транзакций CICS для z / OS 5.3.0
- WebSphere Application Server 8.5.5.8
- Hibernate 5.1.0
Обновление: просто чтобы уточнить, что после запуска нашего приложения оно может без проблем запрашивать DB2 (при обслуживании HTTP-запросов). Проблема связана только с запуском.
2 ответа
Следующее решение было протестировано, чтобы работать нормально.
Идея состоит в том, чтобы выполнить операторы 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
метод принятия Callable
, что может быть полезно для упрощения ветки CICS execute
метод что-то вроде этого:
CICSExecutorService.runAsCICS(() -> { runnable.run(); return null; }).get();
Несколько альтернативных вариантов:
- Завершение только действия по установлению соединения (
org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl#getConnection
) не работал, так как соединение было закрыто уже при использовании в основном потоке. - Завершение запуска всего приложения (
org.springframework.web.context.ContextLoaderListener#contextInitialized
) привело к проблемам с загрузкой классов.
Изменить: в конечном итоге пошел с пользовательским Hibernate's MultiTableBulkIdStrategy
реализация, которая не запускает SQL/DDL при запуске ( см. страницу проекта на GitHub).
Поддержка CICS TS v5.3 для функции JPA в Liberty была недавно доступна в обновлении службы (июль 2016 г.). До этого обновления попытка запустить JPA в приложениях привела бы к проблемам, аналогичным тем, которые вы описали.
Хотя вы работаете в режиме гибернации и находитесь в потоке с поддержкой CICS, у него нет среды API (что позволит успешно выполнять вызов JDBC типа 2). Новая логика обнаружения была разработана специально (но не исключительно) для использования с драйвером DB2 JDBC типа 2 и JPA. Это обновление было добавлено в недавнем обновлении службы и может устранить проблемы, с которыми вы столкнулись.
Попробуйте подать заявку: http://www-01.ibm.com/support/docview.wss?crawler=1&uid=swg1PI58375
В описании говорится, что оно предназначено для поддержки "стандартного режима Liberty", но оно содержит и другие разработки, описанные выше.