【问题标题】:How to start a transaction in JPA using entityManager如何使用 entityManager 在 JPA 中启动事务
【发布时间】:2017-08-11 12:49:19
【问题描述】:

我已经开始开发一个使用 spring、hibernate、JPA、SOAP webservices 的应用程序。现在要求某些查询必须在事务中运行。如果任何一个失败,整个事务应该回滚。

dao层代码如下:

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;
import org.hibernate.Session;

    public class BillDAOImpl implements BillDao{

             @PersistenceContext(type = PersistenceContextType.EXTENDED)
             private EntityManager em;

             public boolean processBills() throws Exception{

             EntityTransaction tx = null;
             Session session = null;

             try{

                 session = em.unwrap(Session.class);
                 tx = em.getTransaction();

                 Bill bill = em.find(Bill.class, billId);

                 //session.beginTransaction();
                 tx.begin();
                 ...
                 ...
                 em.persist(bill);
                 ...
                 ...
                 em.merge(<other object>);
                 ...
                 ...
                 //session.getTransaction().commit();
                 tx.commit();
             } catch(){
             }

             }

    }

当它执行tx = em.getTransaction() 时,会出现以下错误:

java.lang.IllegalStateException: Cannot execute getTransaction() on a container-managed EntityManager

其他交易相关属性如下:

<bean id="tuneEntityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        p:persistenceXmlLocation="classpath*:META-INF/tune-persistence.xml"
        p:persistenceUnitName="tunePersistenceUnit" p:loadTimeWeaver-ref="loadTimeWeaver"
        p:jpaVendorAdapter-ref="jpaVendorAdapter" p:jpaDialect-ref="jpaDialect"
        p:dataSource-ref="tuneDbDataSource">
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.BTMTransactionManagerLookup
                </prop>
                <prop key="net.sf.ehcache.configurationResourceName">/${tune-db.ehcache.config.file}</prop>
                <prop key="hibernate.transaction.flush_before_completion">false</prop>              
                <prop key="hibernate.default_schema">${tune-db.schema}</prop>
                <prop key="org.hibernate.envers.default_schema">${tune-db.schema}</prop>
                <prop key="javax.persistence.validation.mode">${tune-db.data.validation}</prop>
                <prop key="hibernate.connection.isolation">3</prop>
                <prop key="hibernate.connection.release_mode">auto</prop>
                <prop key="hibernate.show_sql">${tune-db.hibernate.show-sql}</prop>
                <prop key="hibernate.format_sql">${tune-db.hibernate.format-sql}</prop>
            </props>
        </property>     
    </bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="tuneEntityManagerFactory" />
    </bean>

当我使用session.beginTransaction() 和session.getTransaction().commit() 时,它可以正常工作。

但是我想用来自entityManager 的交易替换它。那该怎么办呢?

【问题讨论】:

  • 使用框架。您正在围绕框架(Spring 和 JPA)工作。而是使用框架(也许首先对它们进行一些阅读)。

标签: java spring hibernate jpa transactions


【解决方案1】:

尝试注入 EntityManagerFactory,然后手动创建 EntityManager:

@PersistenceUnit
private EntityManagerFactory entityManagerFactory;

public boolean processBills() throws Exception{

   EntityManager em = entityManagerFactory.createEntityManager();

   EntityTransaction tx = null;

   Session session = null;

   try{

       session = em.unwrap(Session.class);
       tx = em.getTransaction();

【讨论】:

  • 使用 Jpa EntityManager 的难点在于在“进程”上设计代码来管理事务并关闭 jboss doc 建议的资源
【解决方案2】:

添加一个值为true 的hibernate.jta.allowTransactionAccess 属性,您应该可以手动使用它。虽然混合策略不是一个好习惯,但有些代码由 JTA 管理,有些是手动管理的。

【讨论】:

    【解决方案3】:

    @PersistenceContext 返回的 EntityManager 实例始终是容器管理的 EntityManager。容器管理的 EntityManager 始终是 JTA EntityManager,因此它们的生命周期由容器管理。我想现在可以理解为什么在它们上调用 getTransaction() 是非法的了。This might help

    【讨论】:

    • 好的。我明白了这一点。但是 session.beginTransaction() 和 session.commit() 有效。休眠会话对象是如何工作的?
    • 我怀疑它是否正常工作,因为我实现了你的代码我得到了 Transaction already active excption。
    【解决方案4】:

    【讨论】:

    • 实际上我没有使用@Transactional,因为在代码中,我们正在调用一个存储过程,当尝试在事务中运行时会引发异常。所以我在存储过程调用之前对查询执行 session.beginTransaction() 和 session.getTransaction().commit(),然后在存储过程调用之后,再次执行 session.beginTransaction() 和 session.getTransaction().commit () .
    • 你在使用@Transactional的时候会遇到什么样的异常?
    • 然后解决这个问题,而不是到处乱搞。您现在遇到的问题是您有 2 个事务并且您无法回滚第一部分...您的这个 hack 正在失去 ACID 属性...
    • 如果我使用@Transactional,它将是容器管理器事务还是应用程序管理事务?还有,是直接注入entityManager还是注入entitymanagerfactory并从中获取entityManager?
    • @Transactional 将成为应用程序管理的事务。容器管理器事务是什么意思?我不清楚 entityManager 应该如何注入。我使用 spring-data-jpa 并且不需要您访问 entityManager ,除非您需要定义自己的自定义查询。当我定义我的自定义存储库(以及其中的查询)时,spring 以 EntityManager 作为参数调用构造函数并使用它。
    猜你喜欢
    • 2012-06-28
    • 1970-01-01
    • 2011-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 2017-07-25
    • 2023-03-26
    相关资源
    最近更新 更多