"Unsupported use of GenericConnection" 从 JPA2.0 迁移到 JPA 2.1 时出现异常

"Unsupported use of GenericConnection" exception when migration from JPA2.0 to JPA 2.1

我们正在从 WAS 8.5 迁移(它使用 openJPA 用于 JPA 2.0,Hibernate 4.2.x [last JPA 2.0 版本]) 到 WAS 9.0(它使用 eclipseLink 用于 JPA 2.1 和 Hibernate 5.2.18 [最后的 JPA 2.1 版本]),除了一件事,迁移是成功的。

为了能够在服务器上多次部署相同的应用程序并针对不同的数据库 运行 我们在 persistence.xml:[=31= 中定义了一个变量 DataSource 引用]

  <persistence-unit name="App_DB" transaction-type="JTA">

    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <jta-data-source>java:comp/env/jdbc/app/dataSourceRef</jta-data-source>

    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle12cDialect" />
      <property name="connection.autocommit" value="false" />           

      <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.WebSphereExtendedJTATransactionLookup" />
      <property name="jta.UserTransaction" value="java:comp/UserTransaction" />

      <property name="hibernate.hbm2ddl.auto" value="validate" />
      <property name="javax.persistence.validation.mode" value="none" />
    </properties>

  </persistence-unit>

如您所见,<jta-data-source> 是参考。引用绑定在 ibm-ejb-jar-bnd.xml

<session name="StartUpService">
  <resource-ref name="jdbc/app/dataSourceRef" binding-name="jdbc/app/appDB"/>
</session>

并在 class 中使用如下:

@Singleton
@Startup
@LocalBean
public class StartUpService {

  @Resource(name = "jdbc/app/dataSourceRef", type = DataSource.class)
  DataSource dataSource;  

}

这对 WAS 8.5 / openJPA 来说一切正常。但是当使用 WAS 9.0 / eclipseLink 时,这不再有效,并在您尝试启动应用程序时产生以下异常:

[WebContainer : 4] ERROR org.hibernate.hql.spi.id.IdTableHelper - Unable to use JDBC Connection to create Statement java.sql.SQLException: Unsupported use of GenericConnection. A GenericConnection is provided during application start when creating an EntityManagerFactory for a persistence unit which has configured one of its datasource to be in the component naming context; java:comp/env. During application start, the component naming context will not exist, and the correct datasource cannot be determined. When the persistence unit is used, the proper datasource and connection will be obtained and used. at com.ibm.ws.jpa.management.GenericConnection.unsupportedUseSQLException(GenericConnection.java:636) ~[com.ibm.ws.runtime.jar:?] at com.ibm.ws.jpa.management.GenericConnection.createStatement(GenericConnection.java:144) ~[com.ibm.ws.runtime.jar:?] at org.hibernate.hql.spi.id.IdTableHelper.executeIdTableCreationStatements(IdTableHelper.java:77) [org.hibernate-hibernate-core-5.2.18.Final.jar:5.2.18.Final] at org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy.finishPreparation(GlobalTemporaryTableBulkIdStrategy.java:125) [org.hibernate-hibernate-core-5.2.18.Final.jar:5.2.18.Final] at org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy.finishPreparation(GlobalTemporaryTableBulkIdStrategy.java:42) [org.hibernate-hibernate-core-5.2.18.Final.jar:5.2.18.Final] at org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl.prepare(AbstractMultiTableBulkIdStrategyImpl.java:88) [org.hibernate-hibernate-core-5.2.18.Final.jar:5.2.18.Final] at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:305) [org.hibernate-hibernate-core-5.2.18.Final.jar:5.2.18.Final] at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462) [org.hibernate-hibernate-core-5.2.18.Final.jar:5.2.18.Final] at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:945) [org.hibernate-hibernate-core-5.2.18.Final.jar:5.2.18.Final] at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:151) [org.hibernate-hibernate-core-5.2.18.Final.jar:5.2.18.Final] at com.ibm.ws.jpa.management.JPAPUnitInfo.createEMFactory(JPAPUnitInfo.java:1161) [com.ibm.ws.runtime.jar:?]

 [...]

at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1909) [com.ibm.ws.runtime.jar:?]

[WebContainer : 4] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Unsupported use of GenericConnection. A GenericConnection is provided during application start when creating an EntityManagerFactory for a persistence unit which has configured one of its datasource to be in the component naming context; java:comp/env. During application start, the component naming context will not exist, and the correct datasource cannot be determined. When the persistence unit is used, the proper datasource and connection will be obtained and used.

000000a1 JPAPUnitInfo E CWWJP0015E: An error occurred in the org.hibernate.jpa.HibernatePersistenceProvider persistence provider when it attempted to create the container entity manager factory for the App_DB persistence unit. The following error occurred: [PersistenceUnit: App_DB] Unable to build Hibernate SessionFactory

因此 Hibernate 似乎无法确定 DataSource。当我设置 <jta-data-source> 的完整 JDNI 名称而不是像这样的引用时

<jta-data-source>jdbc/app/appDB</jta-data-source> 

应用程序完美启动,Hibernate 可以在启动时进行架构验证。

当我在网上搜索这个问题时,我发现 suggestion 你应该将 javax.persistence.jtaDataSource" 添加到 persistence.xml<jta-data-source> 相同的值像这样:

<property name="javax.persistence.jtaDataSource" value="java:comp/env/jdbc/app/dataSourceRef" />

但这并没有改变我的情况。同样的错误,没有成功启动。

所以我很想知道以下问题的答案:

  1. 主要问题:如何定义我的 persistence.xml 以再次使用 DataSource 引用?如果启动验证是针对应用程序的所有实例的同一个数据库进行的,即使 运行ning 应用程序在启动后会使用另一个数据源,因为我显然想验证 DataSource 实例真正使用。 注意:更改 JPA 实现不会由我们的管理员完成 - 他们只坚持 IBM 支持的原始配置原因。

  2. 小问题:为什么 Hibernate (4.2.x) 结合 openJPA 可以使用 WAS 8.5 中的引用,但 Hibernate (5.2.18) 结合 eclipseLink 可以'在 WAS 9.0 中不能这样做吗?

去更新一下吧。我的 post 不是一个有效解决方案的答案,而是对发生的情况(据我了解)以及失败的原因进行了进一步的解释。并且在它是我为工作写的分析的缩短版本(超过 4 页)之前说,因为我不想完全从德语翻译(我的英语很糟糕)并且它们基于我可以的几个日志文件'不要在这里发表。

td;dr

IBM 必须更改 WAS 9。

长话短说

在与我们的管理员再次交谈后,我做了进一步的研究:

错误 Unsupported use of GenericConnection 由 IBM 抛出,甚至在 WAS 8.5 / Hibernate 4 上抛出。2.x 但 WAS/Hiberante 组合以另一种方式工作,如 9.0/5。 2.x

IdTableHelper 尝试在连接对象 (Statement statement = connection.createStatement();) 上创建语句时(在 5.2 中)抛出错误 Unable to use JDBC Connection to create Statement,该连接对象是由 EntityManagerFactory 创建的.我想知道为什么一个错误说它无法提供连接?我得出的结论是 WAS 返回某种代理项,否则,如果连接为 NULL,则错误消息将是 Unable obtain JDBC Connection,这将在 Hibernates 代码中更早地触发。

进一步研究:

启动应用程序(例如,通过单击管理控制台中的 start)启动阶段包括两个阶段:首先启动容器,重新注册 EJB、JTA、JMS、JPA 等. 然后启动应用程序并启动所有启动 beans(用 @StartUp 注释的 beans)。当出现 WAS 认为严重的错误时,启动失败。

创建实体管理器时,Hibernates 会尝试验证架构(在 hbm2dll=validate 上)。

当深入研究日志时,我发现在 Hibernate 4.2 中,由于没有连接,在设置 JPA 期间出现了两次错误,但是当启动 bean 时,日志显示 persistence.xml 被再次解析并且连接可以由 WAS 提供。至此,架构验证成功。在设置 JPA 期间,错误消息出现两次,因为检索元数据和尝试验证在 Hibernate 4.2 中的两个 try/catch 块中。

当使用WAS9/Hibernate 5.2 时,错误消息被记录下来并且启动失败。该消息仅记录一次,因为检索元数据和进行验证是在同一个 try/catch 块中,并且在接收元数据时已经失败。此错误仍然不会中断应用程序的启动。但与 WAS 8.5/4.2 不同的是,当启动 bean 启动时,启动过程失败,因为没有实体管理器可以提供给 bean。日志还显示 persistence.xml 没有被再次解析。所以 WAS 不会尝试第二次提供实体管理器。

因此,如果没有 "fix" 或者我们称之为 WAS 9 的更改,则无法使用数据源引用。我怀疑这是否会发生...

关于更多:

上面提到的IdTableHelperclass是Hibernates Bulk策略的基本类,可以抛出错误信息的两种方法尝试执行create或delete语句。由于应用程序的数据库用户没有 DDL 权限,我在想这是否会成为一个问题,以及我是否可以通过将休眠的批量策略更改为 org.hibernate.hql.spi.id.inline.InlineIdsInClauseBulkIdStrategy 来更改行为,其中没有为级联操作创建表。但这并没有改变任何东西,因为仍然需要用于模式验证的元数据。

对我有帮助的解决方案:

<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/myTest</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.target-database" value="Oracle"/>
<property name="eclipselink.target-server" value="WebSphere"/>
<property name="eclipselink.logging.level" value="FINEST"/>
<property name="javax.persistence.jtaDataSource" value="jdbc/myTest" />
</properties>
</persistence-unit>

所以基本上错误通过 属性 声明确认了 jtaDataSource。

最后但同样重要的是,删除:

java:comp/env/jdbc/myTest

并放置简单的 JNDI 参考:

jdbc/myTest