Spring @Transactional没有创建所需的事务

时间:2010-03-11 17:29:27

标签: spring jpa transactional

好的,所以我终于屈服于同伴压力并开始在我的网络应用中使用Spring: - )...

所以我试图让事务处理工作起作用,而我似乎无法得到它。

My 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)

此外,Spring首次启动时会收到以下警告。由于这些引用了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.springframework.beans.factory.support.DefaultListableBeanFactory@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

有没有人知道我错过了什么?我完全被难过......

由于

3 个答案:

答案 0 :(得分:17)

EntityManagerFactory.createEntityManager()获得的实体管理器实例不参与Spring管理的交易。

获取实体管理器的常用方法是使用@PersistenceContext - 注释属性注入它:

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

答案 1 :(得分:5)

问题可能是由您注释受保护的方法和使用proxy-target-class="true"的组合引起的。这是一个糟糕的组合。 Spring生成的事务代理只能使用公共注释方法正常工作,但如果不是,则不会抱怨。

尝试将saveOrUpdate()方法公开,或者更好的是,为DAO定义接口,并删除proxy-target-class="true"设置。这是最安全,最可预测的技术。

答案 2 :(得分:0)

就我而言:

将JPA与Spring MVC一起使用 - 我的所有测试和代码运行良好而没有错误 - 症状是,无论我尝试什么,提交都不会保存到数据库中。

我不得不补充一下 到我的applicationContext.xml和cglib-nodep-2.1_3.jar aopalliance-1.0.jar

我的情况肯定是修复。没有注释驱动的Spring将不会扫描@Transactional注释