【问题标题】:Using EAR-level defined data source as JTA data source in persistence.xml of a shared JAR在共享 JAR 的 persistence.xml 中使用 EAR 级定义的数据源作为 JTA 数据源
【发布时间】:2020-10-28 05:52:08
【问题描述】:

在 Jakarta EE 8 环境中:是否可以在 application.xml 中定义 EAR 级别 [1] 的(“可移植 JNDI”)数据源,并将此数据源用作 persistence.xml 中的 JTA 数据源在库/JAR 模块中?

目的:创建一个通用的 JAR 模块,定义 JPA 实体以及相应的“存储库”,以便这个 JAR 模块可以被多个 WAR 模块(例如一个 RESTful API 和一个 UI 模块)使用,并将这个模块打包为一个 EAR可部署到多个应用服务器

使用以下尝试/方法(对于一个完整的示例,我创建了一个简单的 git 存储库 [2]),这种 EAR 的部署失败(至少对于 Payara 和 WildFly)。


尝试/方法

假设有一个由 2 个 WAR 模块组成的应用程序,并且两个 WAR 模块都使用一个共享的 JAR 模块,因此应用程序结构类似于:

ear/
├── shared-lib-jar
|   ├── ...
|   └── META-INF
|       ├── ...
|       └── persistence.xml
├── api-war/
|   └── ...
├── ui-war/
|   └── ...
├── application.xml
├── ...

在 EAR 的 application.xml 中,数据源的定义如下:

<application>
  <!-- ... -->
  <data-source>
    <name>java:app/appDS</name>
    <!-- ... -->
  </data-source>
</application>

persistence.xml 中,application.xml 中定义的 JNDI 名称用作 JTA 数据源:

<persistence>
  <persistence-unit name="..." transaction-type="JTA">
    <jta-data-source>java:app/appDS</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <!-- ... -->
  </persistence-unit>
</persistence>

不同 (2) 应用服务器的意外/错误行为/情况

设置:org.h2.jdbcx.JdbcDataSourceclass-name 和“基于文件”的数据库

Payara (5.2020.2)

不会创建数据库文件,服务器日志显示:

[2020-07-07T22:56:32.731+0200] [Payara 5.2020] [SEVERE] [AS-DEPLOYMENT-00026] [javax.enterprise.system.tools.deployment.dol] [tid: _ThreadID=168 _ThreadName=admin-thread-pool::admin-listener(11)] [timeMillis: 1594155392731] [levelValue: 1000] [[
  JNDI lookup failed for the resource: Name: foo-core, Lookup: java:app/appDS, Type: javax.sql.DataSource.]]

[2020-07-07T22:56:32.731+0200] [Payara 5.2020] [SEVERE] [] [javax.enterprise.system.core] [tid: _ThreadID=168 _ThreadName=admin-thread-pool::admin-listener(11)] [timeMillis: 1594155392731] [levelValue: 1000] [[
  JNDI lookup failed for the resource: Name: [foo-core], Lookup: [java:app/appDS], Type: [javax.sql.DataSource]]]

WildFly (1.4.11.Final)

数据库文件已创建,但服务器日志显示:

{"WFLYCTL0062: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"foo-ear-0.0.1-SNAPSHOT.ear\".WeldStartService" => "Failed to start service
    Caused by: java.lang.IllegalArgumentException: WFLYWELD0037: Error injecting persistence unit into CDI managed bean. Can't find a persistence unit named 'foo-core' in deployment foo-ear-0.0.1-SNAPSHOT.ear for injection point protected javax.persistence.EntityManager com.acme.BookRepository.entityManager"}}}}

1:https://jakarta.ee/specifications/platform/8/platform-spec-8.html#a1688

2:https://gitlab.com/hjoeren/application-level-ds-example

【问题讨论】:

    标签: jpa jakarta-ee wildfly ear payara


    【解决方案1】:

    是的,您几乎完成了,至少在 Payara 或 Glasshish 的情况下。您不需要在 application.xml 中公开您的数据源。

    首先像你做的那样在persistence.xml声明你的数据源:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
      <persistence-unit name="my.PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        **<jta-data-source>jdbc/mydatasource</jta-data-source>**
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
          <property name="eclipselink.logging.level" value="INFO"/>
          <property name="eclipselink.logging.parameters" value="true"/>
          <property name="eclipselink.persistence-context.flush-mode" value="COMMIT"/>
        </properties>
      </persistence-unit>
    </persistence>
    

    然后只需使用管理控制台或 asadmin 命令在您的 Payara(或 GF)应用服务器上配置适当的连接池和 JDBC 资源。 glassfish-resources.xml 文件示例

    $cat glassfish-resources.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">    
        <resources>
            <jdbc-connection-pool connection-creation-retry-interval-in-seconds="30" connection-validation-method="auto-commit" datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" wrap-jdbc-objects="false" res-type="javax.sql.DataSource" `name="mysql_myrootPool"` is-connection-validation-required="true" connection-creation-retry-attempts="10" validate-atmost-once-period-in-seconds="60">
                <property name="User" value="root"/>
                <property name="Password" value="secret"/>
                <property name="URL" value="jdbc:mysql://localhost:3306/mydb?zeroDateTimeBehavior=convertToNull"/>
                <property name="driverClass" value="com.mysql.jdbc.Driver"/>
                <property name="zeroDateTimeBehavior" value="convertToNull"/>
                <property name="characterEncoding" value="utf-8"/>
                <property name="useSSL" value="false"/>
            </jdbc-connection-pool>
            <jdbc-resource enabled="true" `jndi-name="jdbc/mydatasource"` object-type="user" `pool-name="mysql_myrootPool"`/>
        </resources>
    $asadmin add-resources glassfish-resources.xml
    

    请注意池、持久性单元和资源的正确名称。

    现在您可以像这样在您的 EAR 中包含的任何 EJB 或 WEB 模块中在任何允许的位置(EJB、Servlet、拦截器等)注入您的连接

    @PersistenceContext(unitName = "my.PU")
    private EntityManager em;
    

    【讨论】:

    • 感谢@s-kadakov 的回答。我知道,使用 Payara/Glassfish,我可以通过 glassfish-resources.xml 声明 JDBC 资源。但正如问题中提到的,我正在寻找一些 application-server Independent 方法(“...可部署到多个应用程序服务器”),因此希望使用application.xml,因为它是一个标准定义数据源的方式不用担心使用的应用服务器
    • 我想WildFly服务器中也可以声明数据源(docs.jboss.org/author/display/WFLY10/…),所以这是纯粹的部署问题。
    • 是的,你是对的:在 WildFly 中也可以声明数据源。但是,如果有办法以每个应用程序服务器都必须理解的供应商中立格式声明数据源,为什么还要以几种供应商特定的方式声明数据源(请参阅5.18.3 of Jakarta EE 8 Spec
    • 环境探索是部署工程师的职责。使用硬编码的数据源,您会迫使客户在每次环境更改(例如 IP 更改)时重新打包您的应用程序,而这正是程序员所需要的。另一方面,当您在虚拟环境中部署并可以使用环境变量对其进行调整时,这不是问题。
    【解决方案2】:

    终于找到错误了:我把application.xml放错了文件夹。与其将application.xml 放在根文件夹中,不如将其放置在META-INF 文件夹的更深处,以便项目结构如下所示:

    ear/
    ├── shared-lib-jar
    |   ├── ...
    |   └── META-INF
    |       ├── ...
    |       └── persistence.xml
    ├── api-war/
    |   └── ...
    ├── ui-war/
    |   └── ...
    ├── META-INF/
    |   ├── ...
    |   └──application.xml
    ├── ...
    

    为了查看完整的示例,我为这个问题修复了repo 中的错误配置

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-14
      • 1970-01-01
      • 1970-01-01
      • 2015-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多