2013-02-28 43 views
9

编辑:对于可能对此问题感兴趣的人,我提供了与问题相关的解决方案问题的结尾。使用Spring数据JPA,Hibernate和多事务管理器:没有定义名为'transactionManager'的bean

我正在为Web应用程序配置一个模块,其中我使用了Spring 3.2,Hibernate 4.1,Spring Data JPA 1.3和Apache CXF 2.5(特别是JAX-RS模块)。我有以下的配置(这是工作完全正常,具体是为了简洁起见,省略):

@Bean(name = "entityManagerFactory") 
    public LocalContainerEntityManagerFactoryBean getEntityManagerFactory() throws SQLException{ 
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); 
    //...  
    return factory; 
    } 

    @Bean(name = "transactionManager") 
    public JpaTransactionManager getTransactionManager() throws SQLException{ 
    JpaTransactionManager manager = new JpaTransactionManager(); 
    //...  
    return manager; 
    } 

    @Bean(name = "persistenceExceptionTranslator") 
    public PersistenceExceptionTranslator getPersistenceExceptionTranslator(){ 
    return new HibernateExceptionTranslator(); 
    } 

我的问题是,我不得不依靠它自己定义PlatformTransactionManager一些外部模块,所以我发现自己与更多的交易经理同时工作。这个问题很容易通过Transactional.html#value()来解决,所以无论我需要使用@Transactional,我使用我必须用于该事务的事务管理器的名称来限定注释。
我想将我在模块中定义的事务管理器的名称更改为更有意义的内容,以符合外部模块的标准。因此,例如,externalModule1其经理定义为externalModule1TransactionManager,我想有

@Bean(name = "myModuleransactionManager") 
    public JpaTransactionManager getTransactionManager() throws SQLException{ 
    JpaTransactionManager manager = new JpaTransactionManager(); 
    //...  
    return manager; 
    } 

这似乎是很容易的,不幸的是,当我做到这一点的变化(我改变@Transactional#value()使用相应我得到一个异常。

java.lang.RuntimeException: org.apache.cxf.interceptor.Fault: No bean named 'transactionManager' is defined 
    at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:110) 
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:323) 
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:123) 
    at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:207) 
    at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:213) 
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:154) 
    at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:126) 
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:185) 
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:113) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621) 
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:164) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) 
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) 
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936) 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) 
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004) 
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) 
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) 
    at java.lang.Thread.run(Thread.java:662) 
Caused by: org.apache.cxf.interceptor.Fault: No bean named 'transactionManager' is defined 
    at org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:155) 
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:121) 
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:167) 
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:94) 
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:58) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439) 
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
    at org.apache.cxf.workqueue.SynchronousExecutor.execute(SynchronousExecutor.java:37) 
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:106) 
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263) 
    ... 25 more 
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'transactionManager' is defined 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:568) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1099) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:278) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:246) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:100) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:92) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) 
    at sun.proxy.$Proxy98.save(Unknown Source) 
    at myModule.package.SomeOtherClass.someOtherMethod(SomeOtherClass.java:114) 
    at myModule.package.SomeOtherClass$$FastClassByCGLIB$$2bda5a73.invoke(<generated>) 
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631) 
    at myModule.package.SomeClass$$EnhancerByCGLIB$$37044080.myMethod(<generated>) 
    at myModule.package.SomeClass.someMethod(SomeClass.java:64) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:173) 
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:89) 
    ... 34 more 

特别,我想集中注意力于

myModule.package.SomeOtherClass.someOtherMethod(SomeClass.java:114) 

myModule.package.SomeClass.someMethod(SomeClass.java:64) 

他们的代码看起来像

@Transactional("myModuleransactionManager") 
public ... someOtherMethod(){ 
    ... 
} 

public ... someMethod(){ 
    ... 
} 

所以,在我的理解这个配置应该工作,为什么它抛出异常?是否需要标准的命名事务管理器?还是因为cxf?我在同一个应用程序(example 1,example2)中发现了与多个事务管理器相关的一些问题,但这些问题中接受的答案驱动到我的解决方案。我误解了什么,我做错了什么?
感谢大家愿意阅读这个长长的问题,直到这里!

编辑根据Michail的回答提供完整的解释:使用Spring Data JPA需要定义存储库接口以连接到数据库。 someOtherMethod确实呼唤它被定义为我的库之一:

@Repository("myRepository") 
@Transactional(propagation = Propagation.NESTED, value = "myModuleransactionManager") 
public interface MyRepository extends JpaRepository<MyEntity, Integer> 
{ 

} 

这又看起来不错,但看着JpaRepository实现源码(所以,看org.springframework.data.jpa.repository.support.SimpleJpaRepository我发现save(以及其他更新方法)用@Transactional注解。代码SimpleJpaRepository

@Transactional 
    public <S extends T> S save(S entity) { 

     if (entityInformation.isNew(entity)) { 
      em.persist(entity); 
      return entity; 
     } else { 
      return em.merge(entity); 
     } 
    } 

因此,使用Spring数据JPA默认的事务管理器(在一个名为transactionManager)时是强制性的。对我的目标不好,但至少我现在知道就是这样!

回答

8

看起来像你的someOtherMethod调用任何其他@Transactional组件(某些类与save方法)。我认为它有@Transactinal()(空)注释(它使用默认bean,名称为transactionManager)。

您可能会在stacktrace中看到2个TransactionInterceptor位置。请提供一些细节。

+0

Michail,你的回答驱使我进入正确的方向找到我的问题的根源。我的配置非常好,问题在于[Spring Data Jpa](http://www.springsource.org/spring-data/jpa)。我扩展了你的答案以提供对这个陈述的解释。 – ThanksForAllTheFish 2013-03-01 08:45:41

0

我发现你的问题非常有趣概念。因此能够修改我久已遗忘的一些概念。看起来像它在java配置端的限制。所以,你将不得不求助于有点XML在之间,然后连锁行业事务管理

<tx:annotation-driven transaction-manager="myModuletransactionManager"/> 

,那么你可以给使用transactionManager的。默认SimpleJpaRepository 也将只使用新的。

更新:或您可以通过配置使用这种方式现在还似乎EnableTransactionManagement

+0

我已经有了使用'@ EnableTransactionManagement'注释的Spring配置类,这没有帮助。此外,SimpleJpaRepository的源代码清楚地使用了@ Transaction。Spring文档指出:'如果您要连接的PlatformTransactionManager的bean名称具有名称transactionManager,则可以省略标记中的transaction-manager属性。如果您要依赖注入的PlatformTransactionManager bean具有任何其他名称,则必须显式使用transaction-manager属性,如前面的示例中所述。 – ThanksForAllTheFish 2013-03-01 13:44:57

+0

因此,当使用“@ Transaction”而没有value属性I理解除了标准的名为transactionManager之外,没有办法使用它。我现在继续前进,并且有一些事情要做,但只要我承诺这样的事情,我就会有一个小想法,我想尝试!可能已经在今天晚些时候。然后,我最终会更新这个线程。 – ThanksForAllTheFish 2013-03-01 13:46:07

+0

不,这是为了重写默认的transactionManager bean的名字而已,我相信 – 2013-03-01 15:57:06

4

我怀疑,你只需要确保您的仓​​库使用正确命名的事务管理器在您的@EnableJpaRepositories注释。

@Configuration 
@EnableTransactionManagement 
@EnableJpaRepositories(
     entityManagerFactoryRef = "fooEntityManagerFactory", 
     transactionManagerRef = "fooTransactionManager", 
     basePackages = {"com.sctrcd.multidsdemo.integration.repositories.foo"}) 
public class FooConfig { 
    //... 
} 

我花了一段时间才能找出细节,所以我刚才提供了如何配置Spring数据JPA库与多个数据源来工作的一个更全面的解释:

Multiple jpa:repositories in xml config, how to configure with @EnableJPARepositories using Spring java config?

而一个完整的项目展示在这里:

https://github.com/gratiartis/multids-demo

+0

我结束了使用单个事务管理器(名为'transactionManager',所以Spring JPA很开心),并且有多个数据源。在代码方面,我使用了许多抽象类来定义基本行为和扩展抽象类的特定配置类。也就是说,如果我现在可以弄清楚我是如何做到的,那么我可以在github上创建一个示例项目来分享我的实现。可能有用。 – ThanksForAllTheFish 2013-11-14 11:50:05

1

实际上,有一种方法可以在Spring Data JPA中使用命名的TransactionManager。 这个工作对我来说:

<bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="myEntityManagerFactory" /> 
</bean> 
<tx:annotation-driven transaction-manager="myTransactionManager"/> 

<jpa:repositories base-package="com.xxx.yyy" entity-manager-factory-ref="myEntityManagerFactory" transaction-manager-ref="myTransactionManager"> 
</jpa:repositories> 
0

我在我的业务层合格@Transactional。在我看来,我们可以禁用Spring Data repository中的事务管理,如下所示:

<jpa:repositories base-package="ru.xdsoft.conn.thanksapp.thanks.dao.repository" 
        entity-manager-factory-ref="thanksEntityManagerFactory" 
        enable-default-transactions="false" 
/> 
<jpa:repositories base-package="ru.xdsoft.conn.thanksapp.orgstruct.dao" 
        entity-manager-factory-ref="orgStructEntityManagerFactory" 
        enable-default-transactions="false" 
/> 

通过100%不确定但错误消失。在这里找到它:https://github.com/spring-projects/spring-data-jpa/blob/master/src/test/resources/org/springframework/data/jpa/repository/support/disable-default-transactions.xml

相关问题