J'ai commencé à travailler sur une application qui utilise des services Web Spring, Hibernate, JPA et SOAP. Il est maintenant nécessaire que certaines requêtes soient exécutées dans une transaction. En cas d'échec, la transaction doit être annulée.
Le code dans la couche dao est le suivant:
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(){
}
}
}
Lorsqu'il exécute tx = em.getTransaction()
, il génère l'erreur suivante:
Java.lang.IllegalStateException: Cannot execute getTransaction() on a container-managed EntityManager
Les autres propriétés liées à la transaction sont les suivantes:
<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>
Lorsque j'utilise session.beginTransaction()
et session.getTransaction().commit()
, cela fonctionne correctement.
Cependant, je veux le remplacer par une transaction de entityManager
. Alors qu'est-ce qui devrait être fait?
Essayez d’injecter EntityManagerFactory puis de créer manuellement 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();
L'instance EntityManager renvoyée par @PersistenceContext est toujours un EntityManager géré par conteneur. Et EntityManager géré par conteneur sont toujours des EntityManagers JTA et, par conséquent, leur cycle de vie est géré par le conteneur. Je suppose qu’à présent, il est logique de dire pourquoi il est illégal d’appeler getTransaction () sur eux . Cela pourrait aider
L'annotation @Transactional fera exactement ce dont vous avez besoin.
Ajoutez une propriété hibernate.jta.allowTransactionAccess
avec la valeur true
et vous devriez être autorisé à l'utiliser manuellement. Bien que ce ne soit pas une bonne pratique de mélanger vos stratégies, faire gérer du code par JTA, certains manuellement.