Java 如何使用 entityManager 在 JPA 中启动事务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42900265/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:30:12  来源:igfitidea点击:

How to start a transaction in JPA using entityManager

javaspringhibernatejpatransactions

提问by azaveri7

I have started working on an application which uses spring, hibernate, JPA, SOAP webservices. Now there is a requirement that certain queries have to be run in a transaction. If any one fails, entire transaction should rollback.

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

The code in the dao layer is as follows :

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(){
             }

             }

    }

When it executes tx = em.getTransaction(), it gives following error :

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

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

The other transaction related properties are as follows :

其他与交易相关的属性如下:

<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>

When I use session.beginTransaction()and session.getTransaction().commit(), it works correctly.

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

However I want to replace it with transaction from entityManager. Then what should be done?

但是我想用来自entityManager. 那应该怎么办呢?

回答by Maciej Kowalski

Try injecting EntityManagerFactory and then creating the EntityManager manually:

尝试注入 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();

回答by userJ

The EntityManager instance returned by @PersistenceContext is always a container managed EntityManager. And container managed EntityManager are always JTA EntityManagers and hence their lifecycle is managed by the container. I guess now it makes sense as to why it is illegal to call getTransaction() on them.This might help

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

回答by coladict

The add a hibernate.jta.allowTransactionAccessproperty with the value trueand you should be allowed to use it manually. Though it's not a good practice to mix your strategies, having some code managed by JTA, some manually.

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