2010-03-11 14 views
14

Ok, così ho finalmente ceduto alle pressioni dei coetanei e iniziato a utilizzare Primavera nella mia web app: -) ...Primavera @Transactional non creazione della transazione richiesta

Così sto cercando di ottenere la roba gestione delle transazioni lavorare, e proprio non riesco a capirlo.

La mia configurazione di Spring si presenta così:


<?xml version="1.0" encoding="UTF-8"?> 

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:p="http://www.springframework.org/schema/p" 
     xmlns:tx="http://www.springframework.org/schema/tx" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans.xsd 
          http://www.springframework.org/schema/tx 
          http://www.springframework.org/schema/tx/spring-tx.xsd"> 

    <bean id="groupDao" class="mil.navy.ndms.conops.common.dao.impl.jpa.GroupDao" lazy-init="true"> 
     <property name="entityManagerFactory" ><ref bean="entityManagerFactory"/></property> 
    </bean> 

<!-- enables interpretation of the @Required annotation to ensure that dependency injection actually occures --> 
    <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/> 

    <!-- enables interpretation of the @PersistenceUnit/@PersistenceContext annotations providing convenient 
     access to EntityManagerFactory/EntityManager --> 
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> 

    <!-- uses the persistence unit defined in the META-INF/persistence.xml JPA configuration file --> 
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> 
     <property name="persistenceUnitName" value="CONOPS_PU" /> 
    </bean> 

    <!-- transaction manager for use with a single JPA EntityManagerFactory for transactional data access 
     to a single datasource --> 
    <bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory"/> 
    </bean> 

    <!-- enables interpretation of the @Transactional annotation for declerative transaction managment 
     using the specified JpaTransactionManager --> 
    <tx:annotation-driven transaction-manager="jpaTransactionManager" proxy-target-class="true"/> 

</beans> 

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="CONOPS_PU" transaction-type="RESOURCE_LOCAL"> 

    <provider>org.hibernate.ejb.HibernatePersistence</provider> 

    ... Class mappings removed for brevity... 

    <properties> 

     <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/> 

     <property name="hibernate.connection.autocommit" value="false"/> 
     <property name="hibernate.connection.username" value="****"/> 
     <property name="hibernate.connection.password" value="*****"/> 

     <property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/> 
     <property name="hibernate.connection.url" value="jdbc:oracle:thin:@*****:1521:*****"/> 
     <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/> 
     <property name="hibernate.hbm2ddl.auto" value="create"/> 
     <property name="hibernate.show_sql" value="true"/> 
     <property name="hibernate.format_sql" value="true"/> 

    </properties> 

    </persistence-unit> 

</persistence> 

Il metodo DAO per salvare il mio oggetto di dominio assomiglia a questo:


    @Transactional(propagation=Propagation.REQUIRES_NEW) 
    protected final T saveOrUpdate (T model) 
    { 
     EntityManager em = emf.createEntityManager (); 
     EntityTransaction trans = em.getTransaction (); 

     System.err.println ("Transaction isActive() == " + trans.isActive ()); 

     if (em != null) 
     { 
      try 
      { 
       if (model.getId () != null) 
       { 
        em.persist (model); 
        em.flush(); 
       } 
       else 
       { 
        em.merge (model); 
        em.flush(); 
       } 
      } 
      finally 
      { 
       em.close(); 
      } 
     } 

     return (model); 
    } 

Così ho

prova a salvare una copia dell'oggetto del mio gruppo utilizzando il seguente codice nel mio caso di test:


    context = new ClassPathXmlApplicationContext(configs); 
    dao = (GroupDao)context.getBean("groupDao"); 

    dao.saveOrUpdate (new Group()); 

Questo bombe con la seguente eccezione:


javax.persistence.TransactionRequiredException: no transaction is in progress 
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:301) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37) 
    at java.lang.reflect.Method.invoke(Method.java:600) 
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:341) 
    at $Proxy26.flush(Unknown Source) 
    at mil.navy.ndms.conops.common.dao.impl.jpa.GenericJPADao.saveOrUpdate(GenericJPADao.java:646) 
    at mil.navy.ndms.conops.common.dao.impl.jpa.GroupDao.save(GroupDao.java:641) 
    at mil.navy.ndms.conops.common.dao.impl.jpa.GroupDao$$FastClassByCGLIB$$50343b9b.invoke() 
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149) 
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622) 
    at mil.navy.ndms.conops.common.dao.impl.jpa.GroupDao$$EnhancerByCGLIB$$7359ba58.save() 
    at mil.navy.ndms.conops.common.dao.impl.jpa.GroupDaoTest.testGroupDaoSave(GroupDaoTest.java:91) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37) 
    at java.lang.reflect.Method.invoke(Method.java:600) 
    at junit.framework.TestCase.runTest(TestCase.java:164) 
    at junit.framework.TestCase.runBare(TestCase.java:130) 
    at junit.framework.TestResult$1.protect(TestResult.java:106) 
    at junit.framework.TestResult.runProtected(TestResult.java:124) 
    at junit.framework.TestResult.run(TestResult.java:109) 
    at junit.framework.TestCase.run(TestCase.java:120) 
    at junit.framework.TestSuite.runTest(TestSuite.java:230) 
    at junit.framework.TestSuite.run(TestSuite.java:225) 
    at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) 

Inoltre, ottengo le seguenti avvertenze quando la primavera inizia prima. Dal momento che questi fanno riferimento al EntityManagerFactory e la transactionManager, probabilmente hanno qualche attinenza con il problema, ma io non sono stati in grado di decifrare loro abbastanza per sapere cosa:


Mar 11, 2010 12:19:27 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization 
INFO: Bean 'entityManagerFactory' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 
Mar 11, 2010 12:19:27 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization 
INFO: Bean 'entityManagerFactory' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 
Mar 11, 2010 12:19:27 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization 
INFO: Bean 'jpaTransactionManager' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 
Mar 11, 2010 12:19:27 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization 
INFO: Bean '(inner bean)' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 
Mar 11, 2010 12:19:27 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization 
INFO: Bean '(inner bean)' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 
Mar 11, 2010 12:19:27 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization 
INFO: Bean 'org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 
Mar 11, 2010 12:19:27 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization 
INFO: Bean 'org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 
Mar 11, 2010 12:19:27 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 
INFO: Pre-instantiating singletons in org.s[email protected]37003700: defining beans [groupDao,org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor,org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor,entityManagerFactory,jpaTransactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor]; root of factory hierarchy 

Qualcuno ha idea di cosa mi manca ? Sono totalmente perplesso ...

Grazie

risposta

16

L'istanza di gestore entità ottenuta da EntityManagerFactory.createEntityManager() non partecipa alle transazioni gestite in primavera.

Il solito modo per ottenere un gestore di entità è quello di iniettare utilizzando @PersistenceContext proprietà -annotated:

@PersistenceContext 
public void setEntityManager(EntityManager em) { ... } 
+1

Ho aggiunto @PersistenceContext alla mia classe DAO. Quando lo eseguo ricevo: java.lang.IllegalStateException: Non è consentito creare transazioni su EntityManager condiviso: utilizzare transazioni Spring o EJB CMT invece su org.springframework.orm.jpa.SharedEntityManagerCreator $ SharedEntityManagerInvocationHandler.invoke (SharedEntityManagerCreator.java:155) a $ Proxy27.getTransaction (sorgente sconosciuta) su mil.navy.ndms.conops.common.dao.impl.jpa.GenericJPADao.saveOrUpdate (GenericJPADao.java:634) su mil.navy.ndms.conops.common.dao. impl.jpa.GroupDao.save (GroupDao.java:645) – Steve

+4

@Steve: Non dovresti chiamare 'getTransaction' su questo' EntityManager' – axtavt

+1

Che ce l'ha. Supponevo che potessi almeno ispezionare la transazione corrente per determinare se l'annotazione @Transactional stava creando la transazione. Era semplicemente per scopi debuggin, quindi quando l'ho rimosso, ho ricevuto la mia transazione. Grazie ... – Steve

5

Il problema è probabilmente causato da una combinazione di voi annotare un metodo protetto, e l'utilizzo di proxy-target-class="true". Questo è un brutto mix. Il proxy transazionale generato da Spring funzionerà correttamente solo con metodi public commentati, ma non si lamenterà se non lo sono.

Provare a rendere pubblico il metodo saveOrUpdate() o, meglio ancora, definire un'interfaccia per il DAO e rimuovere l'impostazione proxy-target-class="true". Questa è la tecnica più sicura e più prevedibile.

+0

Il metodo è anche 'final'. Impedisce l'uso di 'proxy-target-class =" true "' anche. – axtavt

+0

Rendere pubblico il metodo fallisce allo stesso modo. – Steve

+0

Anche la rimozione della finale non ha avuto alcun effetto. – Steve

0

Nel mio caso:

Utilizzando JPA con Spring MVC - tutti i miei test e codice di corse bene senza errore - il sintomo era che i commit non sarebbero semplicemente salvati nel database, non importa quello che ho provato.

ho dovuto aggiungere al mio applicationContext.xml e cglib-NODEP-2.1_3.jar aopalliance-1.0.jar

Sicuramente la correzione nel mio caso. Senza l'annotazione guidata, Spring non eseguirà la scansione dell'annotazione @Transactional

+1

Oltre a queste dipendenze come è finito il tuo applicationContext.xml? – Marcelo

Problemi correlati