Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Working with Spring Data JPA, Hibernate and multiple transaction manager: No bean named 'transactionManager' is defined

EDIT: to whoever may be in interested in this issue, I provide the analysys of the problem with the related solution at the end of the question.

I am configuring a module for a web application in which I am using Spring 3.2, Hibernate 4.1, Spring Data JPA 1.3 and Apache CXF 2.5 (in particular the JAX-RS module). I have the following configuration (which is working perfectly fine, detailed are omitted for sake of conciseness):

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

My problem is that I have to rely on some external modules which define their own PlatformTransactionManager, so I find myself working with more transaction manager at the same time. This issue is easily addressed by Transactional.html#value(), so wherever I need to use @Transactional I qualified the annotation with the name of the transaction manager I have to use for that transaction.
I would like to change the name of the transaction manager I define in my module to something more meaningful, to meet the standard of the external modules. So, e.g., externalModule1 defines its manager as externalModule1TransactionManager and I would like to have

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

This seems pretty easy, unfortunately when I do this change (and I change the usage of @Transactional#value() accordingly I get an exception.

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

In particular, I would like to focus the attention on

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

and

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

Their codes look like

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

and

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

So, in my understanding this configuration should work, why does it throw that exception? Is a standard named transaction manager required? Or is it something due to cxf? I found some questions related to multiple transaction manager within the same application (example 1, example2) but the accepted answer in those questions drive to my solution. What did I misunderstand and I am doing wrong?
Thanks to everybody who is willing to read this long question till here!

EDIT to provide a complete explanation based on Michail's answer: using Spring Data JPA there is the need to define repositories interfaces to connect to the database. someOtherMethod is indeed calling one of my repositories which is defined as:

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

}

This again looks fine, but looking at JpaRepository implementation source code (so, looking at org.springframework.data.jpa.repository.support.SimpleJpaRepository I discovered that the save (as well as other update methods) is annotated with @Transactional. Code from SimpleJpaRepository

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

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

Therefore, when using Spring Data JPA the default transaction manager (the one named transactionManager) is mandatory. Bad for my goal, but at least I now know that's it!

like image 610
ThanksForAllTheFish Avatar asked Feb 28 '13 19:02

ThanksForAllTheFish


People also ask

What is use of @transactional annotation in spring?

The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.

What should be the bean name for the Platformtransactionmanager?

A minor difference between the two examples lies in the naming of the TransactionManager bean: In the @Bean case, the name is "txManager" (per the name of the method); in the XML case, the name is "transactionManager".

What is @transactional annotation in spring boot?

The @Transactional annotation is metadata that specifies that an interface, class, or method must have transactional semantics; for example, "start a brand new read-only transaction when this method is invoked, suspending any existing transaction".

What is the use of @transactional in spring boot?

The @Transactional annotation provides the following attributes: value and transactionManager – these attributes can be used to provide a TransactionManager reference to be used when handling the transaction for the annotated block.


2 Answers

Looks like your someOtherMethod calls any other @Transactional component (some class with save method). And I think it has @Transactinal() (empty) annotation (which uses default bean named transactionManager).

You may see 2 TransactionInterceptor positions in stacktrace. Please provide some details about it.

like image 184
Michail Nikolaev Avatar answered Sep 28 '22 15:09

Michail Nikolaev


I suspect that you just need to ensure that your repositories use the correctly named transaction manager in your @EnableJpaRepositories annotation.

i.e.

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

It took me a while to figure out the details, so I have just provided a fuller explanation of how to configure Spring Data JPA repositories to work with multiple datasources here:

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

And a full project demonstrating it here:

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

like image 22
Steve Avatar answered Sep 28 '22 15:09

Steve