2010-03-11 34 views
14

好了,我終於屈服於同行的壓力,並開始在我的web應用程序中使用Spring: - )...春天@Transactional沒有創造所需的事務

所以我試圖讓事務處理的東西工作,我似乎無法得到它。

我的Spring配置如下:


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

的DAO方法來保存我的域對象是這樣的:


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

所以我嘗試在我的測試用例中使用以下代碼保存我的Group對象的副本:


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

    dao.saveOrUpdate (new Group()); 

這種炸彈有以下異常:


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) 

此外,我得到以下警告首次啓動春季時。由於這些引用的entityManagerFactory和transactionManager的,他們可能對問題的一些影響,但是我一直沒有能夠破譯他們足夠的知道:


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 

沒有人有任何想法,我缺少的是什麼?我完全難倒...

感謝

回答

16

EntityManagerFactory.createEntityManager()獲取的實體管理器實例不參與Spring管理的事務。

的常用方法獲得實體管理器是使用@PersistenceContext -annotated屬性注入它:

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

我將@PersistenceContext添加到了我的DAO類。當我運行它時,我得到: java.lang.IllegalStateException:不允許在共享EntityManager上創建事務 - 使用Spring事務或EJB CMT代替org.springframework.orm.jpa.SharedEntityManagerCreator $ SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:155 )at mil.navy.ndms.conops.common.dao.impl.jpa.GenericJPADao.saveOrUpdate(GenericJPADao.java:634)at mil.navy.ndms.conops.common.dao $ Proxy27.getTransaction(Unknown Source)。 impl.jpa.GroupDao.save(GroupDao.java:645) – Steve 2010-03-11 18:00:58

+4

@Steve:你不應該在這個'EntityManager'上調用'getTransaction' – axtavt 2010-03-11 18:07:55

+1

就是這樣。我認爲我至少可以檢查當前事務以確定@Transactional註釋是否正在創建事務。這僅僅是爲了調試的目的,所以當我刪除它,我得到了我的交易。 謝謝... – Steve 2010-03-11 18:14:52

5

的問題可能是由你們共同造成的註釋受保護的方法,以及使用proxy-target-class="true"。這是一個糟糕的組合。 Spring生成的事務代理只能使用公共註釋方法正常工作,但如果它們不是,則不會投訴。

嘗試使saveOrUpdate()方法公開,或者更好的是爲您的DAO定義一個接口,並刪除proxy-target-class="true"設置。這是最安全,最可預測的技術。

+0

該方法也是「final」。它也防止使用'proxy-target-class =「true」'。 – axtavt 2010-03-11 17:35:37

+0

使方法公開失敗的方式相同。 – Steve 2010-03-11 17:37:06

+0

刪除最終也沒有效果。 – Steve 2010-03-11 17:38:25

0

在我的情況:

使用JPA與Spring MVC - 我所有的測試和代碼運行罰款沒有錯誤 - 症狀是提交不會保存到數據庫,無論我嘗試了什麼。

我必須在我的情況下加 我的applicationContext.xml和CGLIB的節點p-2.1_3.jar aopalliance-1.0.jar

絕對的修補程序。如果沒有註釋驅動,Spring將不會掃描@Transactional註釋

+1

除了那些依賴項,你的applicationContext.xml如何結束呢? – Marcelo 2013-07-15 01:07:37

相關問題