2010-03-11 12 views
14

Ok, donc je l'ai finalement cédé à la pression des pairs et commencé à utiliser Spring dans mon application web: -) ...Spring @Transactional ne pas créer transaction requise

Je suis en train de faire les choses la gestion des transactions pour travailler, et je ne peux pas sembler l'avoir.

Ma configuration Spring ressemble à ceci:


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

La méthode DAO pour sauver mon objet de domaine ressemble à ceci:


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

Je essayez d'enregistrer une copie de mon objet Groupe en utilisant le code suivant dans mon cas de test:


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

    dao.saveOrUpdate (new Group()); 

Cette bombes à l'exception suivante:


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) 

De plus, je reçois les avertissements suivants lors du printemps commence d'abord. Étant donné que ces références et la EntityManagerFactory TransactionManager, ils ont probablement une incidence sur le problème, mais je n'ai pas été en mesure de les déchiffrer assez pour savoir ce que:


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 

Est-ce que quelqu'un a une idée de ce que je suis absent ? Je suis totalement déconcerté ...

Merci

Répondre

16

L'instance du gestionnaire d'entités obtenue à partir de EntityManagerFactory.createEntityManager() ne participe pas aux transactions gérées par Spring.

La manière habituelle pour obtenir un gestionnaire d'entités est d'injecter à l'aide @PersistenceContext propriété -annotated:

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

J'ai ajouté @PersistenceContext à ma classe DAO. Quand je l'exécute, je reçois: java.lang.IllegalStateException: Non autorisé à créer une transaction sur EntityManager partagé - utilisez plutôt les transactions Spring ou EJB CMT sur org.springframework.orm.jpa.SharedEntityManagerCreator $ SharedEntityManagerInvocationHandler.invoke (SharedEntityManagerCreator.java:155) à $ Proxy27.getTransaction (source inconnue) à mil.navy.ndms.conops.common.dao.impl.jpa.GenericJPADao.saveOrUpdate (GenericJPADao.java:634) à mil.navy.ndms.conops.common.dao. impl.jpa.GroupDao.save (GroupDao.java:645) – Steve

+4

@Steve: Vous ne devriez pas appeler 'getTransaction' sur ce' EntityManager' – axtavt

+1

Ça y est. J'ai supposé que je pouvais au moins inspecter la transaction en cours pour déterminer si l'annotation @Transactional créait la transaction. C'était simplement à des fins de débogage, alors quand je l'ai enlevé, j'ai eu ma transaction. Merci ... – Steve

5

Le problème est probablement dû à une combinaison de vous annoter une méthode protégée, et en utilisant proxy-target-class="true". C'est un mauvais mélange. Le proxy transactionnel généré par Spring ne fonctionnera correctement qu'avec les méthodes publiques annotées, mais il ne se plaindra pas s'il ne l'est pas.

Essayez de rendre la méthode saveOrUpdate() publique ou, encore mieux, définissez une interface pour votre DAO et supprimez le paramètre proxy-target-class="true". C'est la technique la plus sûre et la plus prévisible.

+0

La méthode est également 'final'. Cela empêche aussi l'utilisation de 'proxy-target-class =" true "'. – axtavt

+0

Rendre la méthode publique échoue de la même manière. – Steve

+0

Retrait de la finale n'a également eu aucun effet. – Steve

0

Dans mon cas:

Utilisation de JPA avec Spring MVC - tous mes tests et le code couru bien sans erreur - le symptôme était que les commits ne sauveraient simplement pas à la base de données n'importe ce que j'ai essayé.

J'ai dû ajouter à mon applicationContext.xml et cglib-nodep-2.1_3.jar aopalliance-1.0.jar

Certainement le correctif dans mon cas. Sans annotation-driven Spring ne recherchera pas l'annotation @Transactional

+1

En plus de ces dépendances comment votre applicationContext.xml a fini? – Marcelo