2013-02-28 23 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

相關問題