【问题标题】:How to get Container Managed Transactions (CMT) working with EJB 3.1, Hibernate 3.6, JPA 2.0 , JBoss and MySQL如何让容器管理事务 (CMT) 与 EJB 3.1、Hibernate 3.6、JPA 2.0、JBoss 和 MySQL 一起使用
【发布时间】:2011-07-20 05:03:40
【问题描述】:

我试图让 CMT 与 JPA EntityManager 和 EJB 一起工作,但出现以下错误。 (堆栈恍惚被截断):

Caused by: java.lang.RuntimeException: **Could not resolve @EJB reference: [EJB Reference: beanInterface 'com.mydomain.beans.TestBean2', beanName 'testBean2', mappedName 'null', lookupName 'null',** owning unit 'AbstractVFSDeploymentContext@2008455195{vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/mydomainWeb.war}']
for environment entry: env/com.mydomain.action.SearchAction/testBean in unit AbstractVFSDeploymentContext@2008455195{vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/mydomainWeb.war}

我的课:

访问会话 Bean 的 Servlet:

public class SearchActionExample extends Action {
    @EJB
    private static TestBeanServiceInterface testBean;

    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        testBean.addSource("TEST SOURCE NAME", 88, 99);
        Service service = testBean.findService("HBA", "MEL");

        return mapping.findForward("success");
    }
}

远程接口:

@Remote
public interface TestBeanServiceInterface {
    // Source is my own custom entity
    void addSource(String sourceName, int newthreadsleeptime, int maxactivehttpclients);

    // Service is my own Custom entity    
    Service findService(String departureAirportCode, String arrivalAirportCode);
}

无状态会话 Bean 定义:

@Stateless
public class TestBeanService implements TestBeanServiceInterface {

    @PersistenceContext(unitName="mydomainJPA")
    private EntityManager em;

    public void addSource(String sourceName, int newthreadsleeptime, int maxactivehttpclients) {
        Source source = new Source();
        source.setName(sourceName);
        source.setNewThreadSleepTime(newthreadsleeptime);
        source.setMaxActiveHttpClients(maxactivehttpclients);
        em.persist(source);
    }
    public Service findService(String departureAirportCode, String arrivalAirportCode) {
        String queryString = "from Service where departureairportcode = '" + departureAirportCode + "' and arrivalairportcode = '" + arrivalAirportCode + "'";
        Service service = (Service)em.createQuery(queryString).getSingleResult();
        return service;
    }
}

文件persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence 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" version="2.0">
<persistence-unit name="mydomainJPA" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/MySqlDS</jta-data-source>
    <class>com.mydomain.entities.Service</class>
<class>com.mydomain.entities.Source</class>
    <properties>
        <property name="hibernate.query.factory_class" value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory"/>
        <property name="hibernate.archive.autodetection" value="class"/>
        <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
        <property name="hibernate.current_session_context_class" value="jta"/>   
    </properties>   
</persistence-unit>

当它说“无法解析引用”时,我还能在哪里定义 bean? EJB3 不需要 ejb-jar.xml。我还缺少其他一些配置文件吗?


更新:

  • 我已经更新了上面的代码段,以便将 bean 创建为接口类型,而不是按照下面的答案。

  • 是否需要在 web.xml 中定义或映射 EJB?

  • 假设 web.xml 中需要引用,我已向 web.xml 添加了一个 EJB 引用(见下文),但现在我收到一个新错误(见下文)

添加到 web.xml 的行:

<ejb-ref>
    <ejb-ref-name>ejb/TestBeanEJBname</ejb-ref-name>
    <ejb-ref-type>Session</ejb-ref-type>
    <home>com.mydomain.action.TestBeanService</home>
    <remote>com.mydomain.action.TestBeanServiceInterface</remote>
 </ejb-ref>

正在收到新的错误消息:

12:11:00,980 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to PostClassLoader: name=vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/purejetWeb.war state=ClassLoader mode=Manual requiredState=PostClassLoader: org.jboss.deployers.spi.DeploymentException: java.lang.IllegalStateException: Failed to find ContainerDependencyMetaData for interface: au.com.purejet.action.TestBeanServiceInterface

Caused by: java.lang.IllegalStateException: Failed to find ContainerDependencyMetaData for interface: com.mydomain.action.TestBeanServiceInterface
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.resolveEjbInterface(MappedReferenceMetaDataResolverDeployer.java:1255) [:6.0.0.Final]
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.resolveEjbRefs(MappedReferenceMetaDataResolverDeployer.java:1099) [:6.0.0.Final]
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.resolve(MappedReferenceMetaDataResolverDeployer.java:807) [:6.0.0.Final]
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.internalDeploy(MappedReferenceMetaDataResolverDeployer.java:181) [:6.0.0.Final]
... 39 more

更新:

“本地”界面可以正常工作(即不必是远程)

我通过在 Eclipse 中的企业应用程序项目中进行部署来使其工作。在 web.xml、ejb-jar.xml 或 application.xml 中不需要对 bean 的引用。

EAR 中的 application.xml 的内容正在部署到 Jboss:

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" id="Application_ID" version="6">
<display-name>myprojects</display-name>
<module>
<web>
<web-uri>myproject.war</web-uri>
<context-root>myproject</context-root>
</web>
</module>
<module>
<ejb>myprojectsEJB.jar</ejb>
</module>
</application>

SessionBean 类:

@Stateless
@Local(SessionBeanLocal.class)

public class SessionBean implements SessionBeanLocal {

@PersistenceContext(unitName="JPAtestProjectPersistenceUnit")
private EntityManager em;

接口类:

@Local
public interface SessionBeanLocal {

TestTiger addTestTiger(String testTigerName);

最重要的改变是:在保存会话的类内部是局部变量,容器(JBoss AS)需要一个设置来创建 bean:

@EJB()
private TestBean3Local beanVariable;

public void setBeanVariable(TestBean3Local beanVariable) {
    System.out.println("=====\n\nSET BEAN VARIABE SETTER WAS CALLED. (BY CONTAINER?)  \n\n=======");
    this.beanVariable = beanVariable;
}

【问题讨论】:

    标签: jpa jboss ejb code-injection entitymanager


    【解决方案1】:

    我得到了一个可行的解决方案:

    @Local 接口可以正常工作(即不必是远程的)

    在 web.xml、ejb-jar.xml、application.xml 或任何 jboss 配置文件中不需要对 bean 的引用。

    我通过在 Eclipse 中的“企业应用程序项目”(EAP) 中进行部署来使其工作。该项目包含“部署程序集”,其中包含包含 JPA 实体类的 .jar,以及包含其他业务逻辑类的另一个 .jar。 EAP 有这两个项目加上 EJB 项目和“动态 Web 项目”(创建一个 .war),在它的构建路径上总共有 4 个项目。 Eclipse 中的 Jboss AS 工具将 EAP 发布/部署到 Jboss 服务器。 EAP 中的 application.xml 的内容正在部署到 Jboss:

    <?xml version="1.0" encoding="UTF-8"?>
    <application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" id="Application_ID" version="6">
        <display-name>myprojects</display-name>
        <module>
            <web>
                <web-uri>myproject.war</web-uri>
                <context-root>myproject</context-root>
            </web>
        </module>
        <module>
            <ejb>myprojectsEJB.jar</ejb>
        </module>
    </application>
    

    本地接口类:

    package com.myproject.beans;
    import javax.ejb.Local;
    
    import com.myproject.entities.Lion;
    
    @Local
    public interface SessionBeanLocal {
    Lion addLion(String lionName);
    }
    

    SessionBean 类:

    package com.myproject.beans;
    
    import javax.ejb.Local;
    import javax.ejb.Stateless;
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    
    import com.myproject.Lion;
    
    @Stateless
    @Local(SessionBeanLocal.class)
    public class SessionBean implements SessionBeanLocal {
    
    @PersistenceContext(unitName="PersistenceUnitNameInPersistenceXML")
    private EntityManager em;
    
    public Lion addLion(String lionName) {
        Lion lion = new Lion(lionName);
        em.persist(lion);
    }
    

    最重要的改变是:在保存会话的类内部是可变的(例如,在 Struts 动作 servlet 内部,但可以是任何 servlet),容器(JBoss AS)需要一个 setter 方法来创建豆子:

    @EJB()
    private SessionBeanLocal bean;
    
    public void setBean(SessionBeanLocal bean) {
        System.out.println("setBean setter was called by container (e.g. Jboss)");
        this.bean = bean;
    }
    
    public exampleStrutsServletMethod(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        PrintWriter out = response.getWriter();
    
        Lion lion = bean.addLion("Simba");  // this will persist the Lion within the persistence-context (and auto-generate an Id), and the container will manage when it's flushed to the database
    
        out.print("<html>LION ID = " + lion.getLionId() + "<html>");
    }
    

    文件persistence.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence 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" version="2.0">
    <persistence-unit name="PersistenceUnitNameInPersistenceXML" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:/MySqlDS</jta-data-source>
        <properties>
        </properties>   
    </persistence-unit>
    

    mysql-dx.xml(在 jboss-server-dir/server/default/deploy 目录中):

    <?xml version="1.0" encoding="UTF-8"?>
    <datasources>
        <local-tx-datasource>
            <jndi-name>MySqlDS</jndi-name>
            <connection-url>jdbc:mysql://localhost:3306/myProjectDatabase</connection-url>
            <driver-class>com.mysql.jdbc.Driver</driver-class>
            <user-name>username</user-name>
            <password>mypassword</password>
            <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
            <metadata>
                <type-mapping>mySQL</type-mapping>
            </metadata>
        </local-tx-datasource>
    </datasources>
    

    注意:如果在 Eclipse 的“Java Persistence”项目属性面板中将“Persistence Class Management”设置为“Discover annotated classes automatically”,则无需在 persistence.xml 中定义类(通过“”) JPA 项目(即包含您的 JPA 2.0 实体类和 persistence.xml 的项目)

    注意:此解决方案基于:EJB3.1、Eclipse Helios SR2、Hibernate 3.6、JPA 2.0、JBoss 6、MySQL 5.5.10

    注意:关于“容器管理事务”(CMT)。 Hibernate 手册引用了它们,并指出您需要将 persistence.xml 属性(例如“hibernate.transaction.factory_class”)设置为值:“org.hibernate.transaction.CMTTransactionFactory”。如果您使用 JPA EntityManager 而不是本机休眠,则情况并非如此。我不需要persistence.xml 中的任何此类自定义CMT 属性。这就是 Hibernate 在实现它的两种方式(即 SessionFactory 与 EntityManager)之间令人困惑的地方。请随时对我的解决方案的这一部分发表更多评论,因为我仍然只是在思考它!会

    【讨论】:

      【解决方案2】:
      public class SearchActionExample extends Action {
          @EJB
          private static TestBeanServiceInterface testBean;
      

      不要对静态字段进行注入,注入是 instance 成员并在创建对象时发生,而静态字段是 class 成员。这很可能是异常的原因。

      【讨论】:

      • 好发现! :) 但是它一直在工作,没有抛出异常。如果它是通过异常实现的,那么这与我原来的问题无关。
      • @willtardy,众所周知,注入不能是静态的,如果声明为 pivate,则必须具有 g/s。即使它与静态一起工作,也应该改变它,你永远不知道它将来会产生什么后果。而且,坦率地说,我不太了解你的问题的状态。如果您解决了,请发布您自己的答案,当他们遇到类似或相同的问题时,它将帮助其他人。
      • 你是对的,“静态”是错误的,实际上它不能与静态一起使用,这是一个错字。我已经发布了一个答案 - 请为我检查它以确保它有意义且准确!干杯,威尔
      • @willtardy,为什么不呢?接受它,欢迎来到 SO! (抱歉耽搁了,有点忙)
      【解决方案3】:

      你需要注入远程接口而不是 Bean

      public class SearchActionExample extends Action {
          @EJB
          private static TestBean2Remote testBean;
      

      【讨论】:

      • 感谢您的回答,但不幸的是它并没有解决问题。我仍然收到错误“java.lang.RuntimeException:无法解析@EJB参考:[EJB参考:beanInterface'com.mydomain.action.TestBeanServiceInterface',beanName'null',mappedName'null',lookupName'null',拥有单位“摘要”
      • 需要在web.xml中定义EJB吗?
      • 视情况而定。你是如何包装整个节目的?如果 .war 和 ejb-jar 在一个 .ear 中,那么一切都应该没问题。如果 ejb 在不同的部署中,您可能需要在应用程序名称前加上前缀,并将其添加到 @EJB 注释中。
      • 我不做任何包装。我在 Eclipse 中有 3 个项目:第一个是包含实体的 JPA 项目。第二个项目包含 DAO 和业务对象类,第三个是当前包含 bean 类的 Web/Servlet 项目。我在 Eclipse 中使用 JBoss 和 JBoss 工具。到目前为止,我还没有进行任何打包,因为我们仍处于初始开发阶段。 “ejb-jar”是什么意思?我需要一个 ejb-jar.xml 文件吗? (我目前没有)。如果打包是一个问题,那么为 EJB、Servlet、jsps 和实体类创建一个 Eclipse 项目是不是一种不好的做法?
      猜你喜欢
      • 2015-11-26
      • 1970-01-01
      • 1970-01-01
      • 2012-09-26
      • 1970-01-01
      • 2012-02-05
      • 2014-09-25
      • 2014-09-08
      • 1970-01-01
      相关资源
      最近更新 更多