2010-03-11 23 views
14

Ok, así que al final he cedido a la presión de grupo y comenzó a usar la primavera en mi aplicación web: -) ...primavera @Transactional no crear transacciones necesario

Así que estoy tratando de conseguir las cosas el tratamiento de transacciones para trabajar, y parece que no puedo conseguirlo.

Mi configuración de la primavera se ve así:


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

El método DAO para salvar mi objeto de dominio tiene el siguiente aspecto:


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

Así que

intente guardar una copia de mi objeto Group usando el siguiente código en mi caso de prueba:


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

    dao.saveOrUpdate (new Group()); 

Este bombas con la siguiente excepción:


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) 

Además, me sale el siguiente advertencias cuando la primavera se inicia por primera vez. Ya que estos hacen referencia a la EntityManagerFactory y la transactionManager, es probable que tengan algo que ver con el problema, pero no han sido capaces de descifrar lo suficiente como para saber qué:


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 

¿Alguien tiene alguna idea de lo que me falta ? Estoy totalmente confundido ...

Gracias

Respuesta

16

La instancia del administrador de entidades obtenida de EntityManagerFactory.createEntityManager() no participa en las transacciones gestionadas por Spring.

La forma habitual para obtener un gestor de la entidad es inyectar usando @PersistenceContext propiedad -annotated:

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

Agregué el @PersistenceContext a mi clase DAO. Cuando lo ejecuto obtengo: java.lang.IllegalStateException: no se permite crear transacciones en EntityManager compartido; utilice transacciones Spring o EJB CMT en su lugar en org.springframework.orm.jpa.SharedEntityManagerCreator $ SharedEntityManagerInvocationHandler.invoke (SharedEntityManagerCreator.java:155) en $ Proxy27.getTransaction (Fuente desconocida) en mil.navy.ndms.conops.common.dao.impl.jpa.GenericJPADao.saveOrUpdate (GenericJPADao.java:634) en mil.navy.ndms.conops.common.dao. impl.jpa.GroupDao.save (GroupDao.java:645) – Steve

+4

@Steve: no debe llamar a 'getTransaction' en este' EntityManager' – axtavt

+1

Eso lo tiene. Supuse que al menos podría inspeccionar la transacción actual para determinar si la anotación @Transactional estaba creando la transacción. Fue simplemente para propósitos de depuración, así que cuando lo eliminé obtuve mi transacción. Gracias ... – Steve

5

El problema es causado probablemente por una combinación de anotar que un método protegido, y el uso de proxy-target-class="true". Esa es una mala combinación. El proxy transaccional generado por Spring solo funcionará correctamente con los métodos anotados públicos, pero no se quejará si no lo son.

Pruebe haciendo público el método saveOrUpdate() o, mejor aún, defina una interfaz para su DAO y elimine la configuración proxy-target-class="true". Esta es la técnica más segura y más predecible.

+0

El método también es 'final'. Impide el uso de 'proxy-target-class =" true "' también. – axtavt

+0

Hacer que el método sea público falla de la misma manera. – Steve

+0

Eliminar el final tampoco tuvo ningún efecto. – Steve

0

En mi caso:

El uso de JPA con Spring MVC - todas mis pruebas y el código corrieron bien sin error - el síntoma fue que los commits simplemente no guardarían en la base de datos sin importar lo que intenté.

he tenido que añadir a mi applicationContext.xml y cglib-nodep-2.1_3.jar aopalliance-1.0.jar

Definitivamente la solución en mi caso. Sin resorte impulsado por anotación no buscará la anotación @Transactional

+1

Además de esas dependencias ¿cómo terminó su applicationContext.xml? – Marcelo

Cuestiones relacionadas