在共享 JAR 的 persistence.xml 中使用 EAR 级别定义的数据源作为 JTA 数据源
Using EAR-level defined data source as JTA data source in persistence.xml of a shared JAR
在 Jakarta EE 8 环境中:是否可以在 application.xml
中的 EAR 级别 [1] 定义(“便携式 JNDI”)数据源并将此数据源用作 JTA 数据source in the persistence.xml
inside a library/JAR module?
目的:创建一个通用的 JAR 模块,它定义了 JPA 实体以及相应的“存储库”,以便这个 JAR 模块可以被多个 WAR 模块使用(例如 RESTful API 和 UI 模块)并将这些模块打包为可部署到 多个应用程序服务器 .
的 EAR
使用以下 attempt/method(作为完整示例,我创建了一个简单的 git 存储库 [2]),此类 EAR 的部署失败(至少对于 Payara 和野蝇)。
Attempt/Method
假设有一个应用程序由 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>
unexpected/faulty behavior/situation 具有不同的 (2) 个应用程序服务器
设置:org.h2.jdbcx.JdbcDataSource
作为class-name
和“基于文件”的数据库
帕亚拉 (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]]]
野蝇 (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
是的,您几乎完成了,至少在 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;
终于找到错误了:我把application.xml
放错了文件夹。不要将 application.xml
放在根文件夹中,而是必须将它放在 META-INF
文件夹的更深一层,这样项目结构如下所示:
ear/
├── shared-lib-jar
| ├── ...
| └── META-INF
| ├── ...
| └── persistence.xml
├── api-war/
| └── ...
├── ui-war/
| └── ...
├── META-INF/
| ├── ...
| └──application.xml
├── ...
为了查看完整示例,我修复了此问题 repo 中的 错误配置 。
在 Jakarta EE 8 环境中:是否可以在 application.xml
中的 EAR 级别 [1] 定义(“便携式 JNDI”)数据源并将此数据源用作 JTA 数据source in the persistence.xml
inside a library/JAR module?
目的:创建一个通用的 JAR 模块,它定义了 JPA 实体以及相应的“存储库”,以便这个 JAR 模块可以被多个 WAR 模块使用(例如 RESTful API 和 UI 模块)并将这些模块打包为可部署到 多个应用程序服务器 .
的 EAR使用以下 attempt/method(作为完整示例,我创建了一个简单的 git 存储库 [2]),此类 EAR 的部署失败(至少对于 Payara 和野蝇)。
Attempt/Method
假设有一个应用程序由 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>
unexpected/faulty behavior/situation 具有不同的 (2) 个应用程序服务器
设置:org.h2.jdbcx.JdbcDataSource
作为class-name
和“基于文件”的数据库
帕亚拉 (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]]]
野蝇 (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
是的,您几乎完成了,至少在 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;
终于找到错误了:我把application.xml
放错了文件夹。不要将 application.xml
放在根文件夹中,而是必须将它放在 META-INF
文件夹的更深一层,这样项目结构如下所示:
ear/
├── shared-lib-jar
| ├── ...
| └── META-INF
| ├── ...
| └── persistence.xml
├── api-war/
| └── ...
├── ui-war/
| └── ...
├── META-INF/
| ├── ...
| └──application.xml
├── ...
为了查看完整示例,我修复了此问题 repo 中的 错误配置 。