如何让容器管理事务(CMT)与EJB3.1、Hibernate3.6、JPA2.0、JBoss和MySQL一起工作

如何让容器管理事务(CMT)与EJB3.1、Hibernate3.6、JPA2.0、JBoss和MySQL一起工作,jpa,jboss,ejb,code-injection,entitymanager,Jpa,Jboss,Ejb,Code Injection,Entitymanager,我试图让CMT与JPA EntityManager和EJB一起工作,但出现了以下错误。(堆栈恍惚状态被截断): 我的班级: 访问会话Bean的Servlet: public class SearchActionExample extends Action { @EJB private static TestBeanServiceInterface testBean; public ActionForward execute(ActionMapping mapping,

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

我的班级:

访问会话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>
<?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>

更新:

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

我通过在Eclipse中的一个企业应用程序项目中部署来实现它。web.xml、ejb-jar.xml或application.xml中不需要引用bean

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

<?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>
<?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>
接口类:

@Local
public interface SessionBeanLocal {

TestTiger addTestTiger(String testTigerName);
package com.myproject.beans;
import javax.ejb.Local;

import com.myproject.entities.Lion;

@Local
public interface SessionBeanLocal {
Lion addLion(String lionName);
}
最重要的改变是:在保存会话的类中,这个类是局部变量,容器(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;
}
@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>");
}

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

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

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

public class SearchActionExample extends Action {
    @EJB
    private static TestBean2Remote testBean;
不要对静态字段进行注入,注入是实例成员,在创建对象时发生,而静态字段是成员。这很可能是异常的原因


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

我已经得到了一个有效的解决方案:

@本地接口工作正常(即不必是远程接口)

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

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

<?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>
<?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;
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 action servlet中,但可以是任何servlet),容器(JBoss AS)需要一个setter方法来创建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;
}
@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>");
}
@EJB()
私有会话bean本地bean;
public void setBean(sessionbeanlocalbean){
System.out.println(“容器(例如Jboss)调用了setBean setter)”;
this.bean=bean;
}
public exampleStrutsServletMethod(ActionMapping映射、ActionForm表单、HttpServletRequest请求、HttpServletResponse响应)引发异常{
PrintWriter out=response.getWriter();
Lion Lion=bean.addLion(“Simba”);//这将在持久化上下文中持久化Lion(并自动生成一个Id),容器将在它刷新到数据库时进行管理
out.print(“LION ID=“+LION.getLionId()+”);
}
文件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>
<?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>

org.hibernate.ejb.HibernatePersistence
java:/MySqlDS

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


MySqlDS
jdbc:mysql://localhost:3306/myProjectDatabase
com.mysql.jdbc.Driver
用户名
我的密码
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
mySQL
注意:如果Eclipse JPA项目(即包含JPA 2.0实体类和persistence.xml的项目)的“Java persistence”项目属性面板中的“persistence class Management”设置为“自动发现带注释的类”,则不需要在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而不是本机hibernate,则情况并非如此。我在persistence.xml中不需要任何这样的定制CMT属性。这就是Hibernate在两种实现方式(即SessionFactory和EntityManager)之间混淆的地方。请随时对我的解决方案的这一部分发表更多意见,因为我仍在绞尽脑汁!Will

我已经获得了一个有效的解决方案:

@本地接口工作正常(即不必是远程接口)

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

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

<?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>
<?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;
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 action servlet中,但可以是任何servlet),容器(JBoss AS)需要一个setter方法来创建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;
}
@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>");
}
@EJB()
私有会话bean本地bean;
public void setBean(sessionbeanlocalbean){
System.out.println(“setB