【问题标题】:Spring @Transactional not creating required transactionSpring @Transactional 未创建所需的事务
【发布时间】:2011-01-26 12:00:45
【问题描述】:

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

所以我试图让事务处理的东西工作,但我似乎无法得到它。

我的 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

有人知道我缺少什么吗?我完全被难住了......

谢谢

【问题讨论】:

    标签: spring jpa transactional


    【解决方案1】:

    EntityManagerFactory.createEntityManager()获取的实体管理器实例不参与Spring管理的事务。

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

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

    【讨论】:

    • 我将@PersistenceContext 添加到我的DAO 类中。当我运行它时,我得到: java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - 在 org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:155) 使用 Spring 事务或 EJB CMT在 $Proxy27.getTransaction(Unknown Source) at mil.navy.ndms.conops.common.dao.impl.jpa.GenericJPADao.saveOrUpdate(GenericJPADao.java:634) at mil.navy.ndms.conops.common.dao.impl .jpa.GroupDao.save(GroupDao.java:645)
    • @Steve:你不应该在这个EntityManager上打电话给getTransaction
    • 就是这样。我假设我至少可以检查当前事务以确定 @Transactional 注释是否正在创建事务。它只是为了调试目的,所以当我删除它时,我得到了我的交易。谢谢...
    • 将 EntityManager 作为字段存储在我的 DAO 中是否会使 DAO 不再是线程安全的?我目前正在使用我的 DAO 的单个实例来处理所有传入的请求。
    • @Steve:不,它没有。 Spring 工厂创建的EntityManager 实例(例如LocalEntityManagerFactoryBean)是线程安全的。
    【解决方案2】:

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

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

    【讨论】:

    • 方法也是final。它也可以防止使用proxy-target-class="true"
    • 公开方法同样失败。
    • 删除final也没有效果。
    • 制作一个我不明白的接口,我已经为DAO定义了一个接口。您是否建议将事务注释放在接口上而不是具体类上?此外,savoOrUpdate 方法位于我的 GroupDao 派生自的基类上。这会导致问题吗?
    • @Steve:是的,我强烈建议您将@Transctional 放在接口方法声明上,或者放在实现该接口的DAO 中的方法定义上。
    【解决方案3】:

    就我而言:

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

    我必须添加 到我的 applicationContext.xml 和 cglib-nodep-2.1_3.jar aopalliance-1.0.jar

    在我的情况下绝对是修复。没有注解驱动的Spring不会扫描@Transactional注解

    【讨论】:

    • 除了这些依赖关系之外,您的 applicationContext.xml 是如何结束的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 2020-04-27
    • 2013-09-22
    • 2019-05-20
    • 1970-01-01
    • 2011-02-21
    • 2015-07-19
    相关资源
    最近更新 更多