web-dev-qa-db-ja.com

Spring @ Transactionalが必要なトランザクションを作成していません

さて、私はついに仲間からの圧力に屈し、私のWebアプリで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>

永続性.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);
    }

そのため、テストケースで次のコードを使用して、グループオブジェクトのコピーを保存しようとしています。


    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

誰かが私が欠けているものを知っていますか?私は完全に困惑しています...

ありがとう

14
Steve

EntityManagerFactory.createEntityManager()から取得したエンティティマネージャーのインスタンスは、Spring管理のトランザクションに参加しません。

エンティティマネージャを取得する通常の方法は、@PersistenceContext-アノテーション付きプロパティを使用してエンティティマネージャを挿入することです。

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

この問題は、保護されたメソッドに注釈を付けることと、_proxy-target-class="true"_を使用することの組み合わせが原因である可能性があります。それは悪いミックスです。 Springによって生成されたトランザクションプロキシは、パブリックアノテーション付きメソッドでのみ適切に機能しますが、そうでない場合でも文句を言うことはありません。

saveOrUpdate()メソッドをパブリックにするか、DAOのインターフェイスを定義して、_proxy-target-class="true"_設定を削除してみてください。これは最も安全で予測可能な手法です。

5
skaffman

私の場合:

Spring MVCでJPAを使用すると(すべてのテストとコードがエラーなしで正常に実行されました)、何を試してもコミットがデータベースに保存されないという症状がありました。

ApplicationContext.xmlとcglib-nodep-2.1_3.jaraopalliance-1.0.jarに追加する必要がありました

私の場合は間違いなく修正されます。アノテーション駆動型がないと、Springは@Transactionalアノテーションをスキャンしません

0
bsautner