How to start a transaction in JPA using entityManager

醉酒当歌 提交于 2019-12-30 04:58:28

问题


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.

The code in the dao layer is as follows :

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 :

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.

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


回答1:


Try injecting EntityManagerFactory and then creating the EntityManager manually:

@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();



回答2:


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




回答3:


The add a hibernate.jta.allowTransactionAccess property with the value true and 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.




回答4:


@Transactional annotation will do exactly what you need.

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative-annotations



来源:https://stackoverflow.com/questions/42900265/how-to-start-a-transaction-in-jpa-using-entitymanager

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!