【问题标题】:Inject EntityManagerFactory using @PersistenceUnit on Jersey with Wildfly在带有 Wildfly 的 Jersey 上使用 @PersistenceUnit 注入 EntityManagerFactory
【发布时间】:2025-11-27 03:50:01
【问题描述】:

我正在尝试使用 @PersistenceUnit 注入 EntityManagerFactory,但它始终为空。

我认为我的 persistence.xml 没问题,因为我可以使用以下代码获取 EntityManager:

EntityManager em = Persistence.createEntityManagerFactory("myPersistenceUnit").createEntityManager();

所以,我想知道我是否做错了什么,或者在使用 Jersey (2.23) 和 Wildfly 10 (JBoss EAP 7) 时这是不可能的。

这是我到目前为止所做的:

  • 在 Eclipse 上创建了 jersey-quickstart-webapp maven 项目;
  • 在我的 pom.xml 中添加了以下依赖项:

    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>7.0</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate.javax.persistence</groupId>
      <artifactId>hibernate-jpa-2.1-api</artifactId>
      <version>1.0.0.Final</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>5.2.2.Final</version>
    </dependency>
    <dependency>
      <groupId>com.hynnet</groupId>
      <artifactId>oracle-driver-ojdbc6</artifactId>
      <version>12.1.0.1</version>
    </dependency>
    
  • 创建了 persistence.xml:

    <persistence-unit name="myPersistenceUnit"
      transaction-type="RESOURCE_LOCAL">
      <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
      <!-- All persistence classes must be listed -->
      <class>com.mps.classes.TermosPesquisados</class>
      <properties>
        <!-- Provider-specific connection properties -->
        <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
        <property name="javax.persistence.jdbc.url" value="JDBC_URL" />
        <property name="javax.persistence.jdbc.user" value="USER" />
        <property name="javax.persistence.jdbc.password" value="PASSWORD" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
        <property name="hibernate.show_sql" value="false" />
        <property name="hibernate.connection.release_mode" value="after_transaction" />
        <property name="hibernate.connection.isolation" value="2" />
      </properties>
    </persistence-unit>
    
  • 修改了MyResource.java:

    @ManagedBean
    @Path("myresource")
    public class MyResource {
    
      @PersistenceUnit(unitName= "myPersistenceUnit")
      private EntityManagerFactory emf;
    
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public String getIt() {
        if(emf == null)
          return "emf is null";
        return "emf is not null";
      }
    }
    
  • 添加了一个空 beans.xml(不确定是否有必要);

【问题讨论】:

  • 附带说明,如果您是 Java 新手并且可以选择自己的工具,我建议您改用 Spring。 Spring Boot 自动配置使这种设置变得更加简单,并且无需外部容器。
  • @chrylis 同意,但可能取决于他的情况......加上过去几年 ejb 变得更容易

标签: java eclipse jersey wildfly


【解决方案1】:

Jersey 似乎与 Resteasy 发生冲突。这样,我有两个选择:

  • 关闭 JBoss/Wildfly 上的 Resteasy(我知道这是可能的,但我不知道怎么做);
  • 移除 Jersey 并改用 Resteasy;

我最终选择了第二个选项,因为它更容易而且我没有理由专门使用 Jersey。

这样,我不得不更改我的 web.xml,替换它:

<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
...
<servlet-mapping>
  <servlet-name>Jersey Web Application</servlet-name>
  <url-pattern>/webapi/*</url-pattern>
</servlet-mapping>

为此:

<servlet-name>javax.ws.rs.core.Application</servlet-name>
...
<servlet-mapping>
  <servlet-name>javax.ws.rs.core.Application</servlet-name>
  <url-pattern>/webapi/*</url-pattern>
</servlet-mapping>

*另一种选择是创建一个扩展应用程序类的类。

*beans.xml 不是必需的。

然后,我用 @Stateless 注释了我的资源类,我能够正确注入 EntityManager:

@Path("myresource")
@Stateless
public class MyResource {

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

此时,EntityManager 没问题,但不知何故它正在使用 JBoss h2 内存数据库 (ExampleDS)。 因此,我在 JBoss (OracleDS) 上配置了一个 oracle 数据源并更新了我的 persistence.xml 以使用 OracleDS 和 JTA 而不是“RESOURCE_LOCAL”:

<persistence-unit name="myPersistenceUnit" transaction-type="JTA">
  <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
  <jta-data-source>java:jboss/datasources/OracleDS</jta-data-source>
...

通过这些步骤,我能够注入 EntityManager 并成功完成我的 CRUD 操作。

【讨论】:

    【解决方案2】:

    @ManagedBean 注释在这里没有意义,这是一个 JSF 注释,我根据你的代码你试图公开一个 REST 层。

    只需删除它,一切都会好起来的(还要确保您的类路径中有 beans.xml 以启用 CDI,否则使用 @Stateless 注释您的类)

    【讨论】:

    • 其实我用的是 javax.annotation.ManagedBean 注解。我删除了 @ManagedBean 并且 EntityManagerFactory 仍然为空。我有一个空 beans.xml,我可以看到 CDI 服务已在控制台日志中启动:[org.jboss.weld.deployer](MSC 服务线程 1-5)WFLYWELD0006:为 CDI 部署启动服务.....
    • 我在课堂上用@Stateless 做了注释,也没有帮助。
    【解决方案3】:

    我认为实体管理器应该足够了:

     @PersistenceUnit(unitName= "myPersistenceUnit")
       private EntityManager em;
    

    【讨论】:

    • 顺便说一句,您不能在托管 bean 中注入实体管理器或实体管理器工厂,您必须将其注入 EJB bean,您必须创建一个 DAO 层,在其中定义您处理数据库,并使用 @EJB 将这些 EJB 注入托管 bean
    • 由于我使用的是 transaction-type="RESOURCE_LOCAL" 我无法注入 EntityManager。我必须注入EntityManagerFactory,否则会出错。
    • 我是 Java 新手,所以让我看看我是否理解“EJB bean”部分。我必须使用我的所有持久性配置创建一个 EJB 项目,创建一个会话 bean 并使用 @EJB 在我的 web/jersey 项目中引用这个 bean?