如何在JBoss AS 6,Hibernate 3.6,JPA,JTA和EJB3中使用容器管理事务(CMT)

时间:2011-03-21 03:41:05

标签: hibernate jpa jboss ejb-3.0 jta

我正在尝试使用CMT设置网络应用。我已经让它在Eclipse中独立运行了,现在我正在尝试使用Struts 1.0在Jboss AS 6中运行它。我选择了CMT,因为我读过的doco暗示它是最好的和“使用最不详细”。所以看起来像Hibernate 3.6的现代/良好实践使用。

我可以使用以下代码提取从MySQL数据库加载对象,但持久化对象不会被刷新/同步/保存到数据库中:

从Struts 1.0 Action类中:

InitialContext ctx = new InitialContext();   
EntityManagerFactory emf = (EntityManagerFactory)ctx.lookup("java:/MyEntityManagerFactory");
然后将'emf'传递给我的DAO类的方法,总结如下:

@PersistenceContext(unitName="purejetJPA") EntityManager em;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
exampleMethodInMyCustomDAOClass() {
EntityManager em = emf.createEntityManager();
em.find(MyCustomEntity.class, 542);  // works successfully
em.persist(newInstanceOfMyCustomEntity);          // this executes ok and generates an ID
                                                  // however the entity is not saved to database upon completion 
}

persistence.xml的内容:

    <?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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_1_0.xsd">
    <persistence-unit name="myPersistanceUnitName" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:/MySqlDS</jta-data-source>
                <class>my.custom.entity.Classes</class>
                <properties>
            <property name="jboss.entity.manager.factory.jndi.name" value="java:/MyEntityManagerFactory"/>
            <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.CMTTransactionFactory"/>
            <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
            <property name="hibernate.connection.autocommit" value="false"/>
            <property name="hibernate.current_session_context_class" value="jta"/>
        </properties>   
    </persistence-unit>
</persistence>

Hibernate EntityManager文档对如何实现CMT的描述非常有限:


我们的CMT和EJB3容器使用的实体管理器/事务管理习惯用法简化为:     //通过注射CMT成语     @PersistenceContext(name =“sample”)EntityManager em;


jboss.org article说:


使用EJB / CMT进行事务划分

我们的目标实际上是从数据访问代码中删除任何事务划分代码:

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void doSomeWork() {

// Do some work
factory.getCurrentSession().load(...);
factory.getCurrentSession().persist(...);
}

我的问题:

  1. 在“actory.getCurrentSession()。load(...);”行中,“factory”是什么类型,我该如何创建它?是Hibernate.SessionFactory吗?还是Jboss或HTTP会话?

  2. 在“@PersistenceContext(name =”sample“)EntityManager em中;”什么是“名字”指的是什么?我在论坛上找到了一个使用“unitName”而不是“name”的例子。这行是如何我首先声明我用来调用.persist()。find()等的EntityManager对象? (因此我的代码不需要创建EntityManagerFactory)

  3. 我应该考虑研究和使用“Java上下文和依赖注入”(CDI)吗?

  4. 任何帮助非常感谢。请让我知道我应该提供的其他代码或配置文件


    更新:

    如果我不使用EntityManagerFactory,并使用@PersistenceContext检索EntityManager,那么我的“会话bean”(基于每个用户会话的类还原+保存实体)的代码应该是这样做的方法?

    @Stateful
    @TransactionManagement(value=TransactionManagementType.BEAN)
    public class X implements IX {
    
    @PersistenceContext(unitName="MySQL", type=PersistenceContextType.EXTENDED)
    private EntityManager em;
    
    @Resource
    private UserTransaction tx;
    
    public void doStuff() {
       tx.begin();
       em.joinTransaction();
       em.find(myEntity);
       em.perrsist(myEntity);
       tx.commit();
    }
    

    如果这是正确的轨道,persistence.xml需要什么?从我对doco和网络的所有阅读中我都不确定可能需要哪些:

    <property name="jboss.entity.manager.factory.jndi.name" value="java:/MyEntityManagerFactory"/>
    <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.CMTTransactionFactory"/>
    <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
    <property name="hibernate.connection.autocommit" value="false"/>
    <property name="hibernate.current_session_context_class" value="jta"/> 
    

2 个答案:

答案 0 :(得分:1)

1)答案与你所链接的文件相同:-)

  

在上面的示例中,您可以看到对SessionFactory的访问。如何在代码中到处访问工厂?同样,如果你在Java EE环境中运行,或者在JSE中使用嵌入式服务,你可以简单地从JNDI查找它,Hibernate可以在启动时绑定它。另一种解决方案是在启动后将其保持在全局静态单例中。

2)name是对persistence-unit标记persistence.xml中指定的名称的引用。在你的情况下,它是myPersistanceUnitName

3)是的,如果你明白它不是要替换任何东西,那就是为了促进“豆”的消费(这可能是来自AS的资源)。

另请注意,为了获得托管的EntityManager(带有好处),您不应该从AS获取EntityManagerFactory。你应该得到EM本身。就像你提到的那样,就像这样:

@PersistenceContext(name="myPersistanceUnitName") EntityManager em;

它只适用于AS管理的东西,比如Servlets,其他CDI bean,EJB ......不确定Struts Action类是否会注入它: - )

答案 1 :(得分:0)

我也有这个问题。我已经缩小到使用@WebService时我们通过@PersistenceContext注入EntityManager,实体管理器为空。

此外,如果我们将数据访问委托给DAO并为DAO类添加@TransactionAttribute(TransactionAttributeType.MANDATORY),则会抛出javax.ejb.EJBTransactionRequiredException

不知道这是否是一个JBoss错误,它没有添加对容器管理事务具有@WebService注释的无状态会话bean。