2013-02-28 7 views
9

EDIT: für wen auch immer in diesem Thema interessiert sein mag, biete ich die Analysis des Problems mit der verwandten Lösung an Ende der Frage.Arbeiten mit Spring Data JPA, Hibernate und Multiple Transaction Manager: Keine Bean namens "transactionManager" ist definiert

Ich konfiguriere ein Modul für eine Webanwendung, in der ich Spring 3.2, Hibernate 4.1, Spring Data JPA 1.3 und Apache CXF 2.5 (insbesondere das JAX-RS-Modul) verwende. Ich habe die folgende Konfiguration (das funktioniert völlig in Ordnung, detailliert aus Gründen der Prägnanz weggelassen):

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

Mein Problem ist, dass ich auf einige externe Module angewiesen sind, die ihre eigenen PlatformTransactionManager definieren, so finde ich mich gleichzeitig mit mehr Transaktionsmanager arbeiten. Dieses Problem wird von Transactional.html#value() leicht behoben, also wo immer ich @Transactional verwenden muss, qualifizierte ich die Annotation mit dem Namen des Transaktionsmanagers, den ich für diese Transaktion verwenden muss.
Ich möchte den Namen des Transaktionsmanagers, den ich in meinem Modul definiere, in etwas aussagekräftigeres ändern, um den Standard der externen Module zu erfüllen. So, zum Beispiel definiert externalModule1 seine Manager als externalModule1TransactionManager und ich würde

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

Dies scheint ziemlich einfach, leider haben möchte, wenn ich diese Änderung zu tun (und ich ändern die Verwendung von @Transactional#value() entsprechend erhalte ich eine Ausnahme.

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 

insbesondere würde Ich mag die Aufmerksamkeit auf

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

und

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

Ihre Codes aussehen

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

und

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

in meinem Verständnis sollte also diese Konfiguration funktioniert, warum es diese Ausnahme nicht werfen? Ist ein Standard namens Transaktionsmanager erforderlich? Oder ist es etwas wegen cxf? Ich habe einige Fragen im Zusammenhang mit mehreren Transaktions-Manager innerhalb der gleichen Anwendung (example 1, example2) gefunden, aber die akzeptierte Antwort in diesen Fragen fahren zu meiner Lösung. Was habe ich falsch verstanden und ich mache falsch?
Danke an alle, die bereit sind, diese lange Frage bis hierher zu lesen!

EDIT eine vollständige Erklärung über Antwort des Michail Basis zur Verfügung zu stellen: mit Spring Data JPA es die Notwendigkeit Repositorys Schnittstellen zu definieren, ist mit der Datenbank zu verbinden. someOtherMethod in der Tat eine meiner Repositories ruft die wie folgt definiert ist:

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

} 

wieder Das sieht gut aus, aber wenn man JpaRepository Codeimplementierung Quelle (so, bei org.springframework.data.jpa.repository.support.SimpleJpaRepository Suche entdeckte ich, dass die save (sowie andere Update-Methoden) ist mit @Transactional annotiert.Code von SimpleJpaRepository

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

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

Wenn daher die Standardtransaktionsmanager Spring Data JPA (die transactionManager genannt) ist obligatorisch. Schlecht für mein Ziel, aber zumindest weiß ich jetzt, dass es das ist!

Antwort

8

Sieht aus wie Ihre someOtherMethod ruft andere @Transactional Komponente (einige Klasse mit save Methode). Und ich denke, es hat @Transactinal() (leere) Annotation (die Standard-Bean mit dem Namen transactionManager verwendet).

Sie können 2 TransactionInterceptor Positionen in Stacktrace sehen. Bitte geben Sie einige Details dazu an.

+0

Michail, Ihre Antwort trieb mich in die richtige Richtung, um die Ursache für mein Problem zu finden. Meine Konfiguration ist völlig in Ordnung, das Problem liegt in [Spring Data Jpa] (http://www.springsource.org/spring-data/jpa). Ich habe Ihre Antwort erweitert, um die Erklärung dieser Aussage zu liefern. – ThanksForAllTheFish

0

Ich fand Ihre Frage sehr interessant conceptully. Und so konnte ich einige meiner längst vergessenen Konzepte überarbeiten. Es sieht so aus, als wäre es eine Einschränkung für die java config-Seite. So müssen Sie ein bisschen xml greifen zwischendurch und dann GIV Transaction so etwas wie

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

dann können Sie Ihre transaction geben verwenden. Standard SimpleJpaRepository wird auch nur das neue verwenden.

Update: oder durch die Art und Weise Sie dies durch Config auch scheint jetzt können es EnableTransactionManagement

+0

Ich habe bereits meine Spring-Konfigurationsklasse mit '@ EnableTransactionManagement' versehen, was nicht hilft. Darüber hinaus verwendet der Quellcode von "SimpleJpaRepository" eindeutig "@ Transaction".In der Spring-Dokumentation heißt es: 'Sie können das Transaktionsmanagerattribut im Tag weglassen, wenn der Bean-Name des PlatformTransactionManager, den Sie verkabeln möchten, den Namen transactionManager hat. Wenn die PlatformTransactionManager-Bean, die Sie in Abhängigkeit einfügen möchten, einen anderen Namen hat, müssen Sie das transaction-manager-Attribut explizit wie im vorherigen Beispiel verwenden. " – ThanksForAllTheFish

+0

Wenn also" @ Transaction "ohne das Wertattribut I verwendet wird zu verstehen, dass es keine andere Möglichkeit als den Standard namens transactionManager gibt. Ich bin jetzt weiter und habe ein paar Sachen zu erledigen, aber sobald ich solche Sachen begehe, werde ich eine kleine Idee haben, die ich ausprobieren möchte! Wahrscheinlich schon heute später. Dann werde ich diesen Thread schließlich aktualisieren. – ThanksForAllTheFish

+0

Nein, das ist für das Überschreiben von Standardtransaktionsmanagern nur der Name, glaube ich –

4

Ich vermute, dass Sie müssen nur sicherstellen, dass Ihre Repositories den richtigen Namen Transaktionsmanager in Ihrem @EnableJpaRepositories Annotation verwenden.

dh

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

Es dauerte eine Weile, um die Details, um herauszufinden, so habe ich vorgesehen nur eine vollständigere Erklärung, wie Spring Data JPA-Repositorys konfigurieren mit mehreren Datenquellen, hier zu arbeiten:

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

und ein komplettes Projekt es hier demonstriert:

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

+0

Ich endete mit einem einzelnen Transaktionsmanager (namens 'transactionManager', so dass Spring JPA glücklich ist), mit mehreren Datenquellen. In Code-Begriffen verwendete ich viele abstrakte Klassen, um grundlegende Verhaltensweisen und spezifische Konfigurationsklassen zu definieren, die die abstrakten erweitern. Das heißt, wenn ich jetzt herausfinden kann, wie ich das gemacht habe, kann ich ein Beispielprojekt auf GitHub erstellen, um meine Implementierung zu teilen. Könnte nützlich sein. – ThanksForAllTheFish

1

Tatsächlich gibt es eine Möglichkeit, den Namen TransactionManager mit Spring Data JPA zu verwenden. Dies funktioniert für mich:

<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

Ich habe qualifiziert @Transactional an meiner Dienstschicht. Und es scheint mir, dass wir das Transaktionsmanagement in Spring Data Repository deaktivieren können, wie folgend:

<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" 
/> 

Nicht sicher um 100%, aber Fehler ist verschwunden. Ich fand es hier: https://github.com/spring-projects/spring-data-jpa/blob/master/src/test/resources/org/springframework/data/jpa/repository/support/disable-default-transactions.xml

Verwandte Themen