当前位置: 动力学知识库 > 问答 > 编程问答 >

jpa - Spring @Transactional not creating required transaction

问题描述:

Ok, so I've finally bowed to peer pressure and started using Spring in my web app :-)...

So I'm trying to get the transaction handling stuff to work, and I just can't seem to get it.

My Spring configuration looks like this:

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

The DAO method to save my domain object looks like this:

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

}

So I try to save a copy of my Group object using the following code in my test case:

context = new ClassPathXmlApplicationContext(configs);

dao = (GroupDao)context.getBean("groupDao");

dao.saveOrUpdate (new Group ());

This bombs with the following exception:

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)

In addition, I get the following warnings when Spring first starts. Since these reference the entityManagerFactory and the transactionManager, they probably have some bearing on the problem, but I've no been able to decipher them enough to know what:

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

Does anyone have any idea what I'm missing? I'm totally stumped...

Thanks

网友答案:

The instance of entity manager obtained from EntityManagerFactory.createEntityManager() doesn't participate in Spring-managed transactions.

The usual way to obtain an entity manager is to inject it using @PersistenceContext-annotated property:

@PersistenceContext
public void setEntityManager(EntityManager em) { ... }
网友答案:

The problem is likely caused by a combination of you annotating a protected method, and using proxy-target-class="true". That's a bad mix. The transactional proxy generated by Spring will only work properly with public annotated methods, but it won't complain if they're not.

Try either making the saveOrUpdate() method public or, better yet, define an interface for your DAO, and remove the proxy-target-class="true" setting. This is the safest, most predictable technique.

网友答案:

In my case:

Using JPA with Spring MVC - all of my tests and code ran fine without error - symptom was that commits would simply not save to the database no matter what I tried.

I had to add to my applicationContext.xml and cglib-nodep-2.1_3.jar aopalliance-1.0.jar

Definitely the fix in my case. Without annotation-driven Spring will not scan for the @Transactional annotation

分享给朋友:
您可能感兴趣的文章:
随机阅读: