springframework.beans.factory.NoUniqueBeanDefinitionException

2k views Asked by At

I am running a spring boot application that communicates with ActiveMQ and a SQL database, and I am facing the following problem: spring cannot auto configure the DB transaction manager for connecting to the database, it will always pick the wrong one (JMSTransactionManager). I am using the JpaRepository interface to communicate with the database, i.e, I am not using entity manager to talk to the database. How can solve this issue?

this is my configuration class


@EnableJms
@EnableTransactionManagement
@Configuration
public class JmsConfig {
    

    
    @Bean
    public PlatformTransactionManager jmsTransactionManager() {
        return new JmsTransactionManager(connectionFactory());
    }
@Bean 
    JpaTransactionManager jpaTransactionManager() {
        JpaTransactionManager manager = new JpaTransactionManager();
        return manager;
    }
    
      
}

I am using both transaction managers on this method

    @Transactional(value="jpaTransactionManager")
    public Image saubmitImage(ImageDirectory dir) {
        return dao.save(new Image());
    }

the error I am getting when I am calling the database is


org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.transaction.TransactionManager' available: expected single matching bean but found 2: jmsTransactionManager,jpaTransactionManager,
    

thanks in advance guys

2

There are 2 answers

2
Justin Bertram On

For your operations to be truly atomic you need to use a JTA transaction manager in order to coordinate the transaction phases (e.g. prepare, commit, rollback) between all the resources (i.e. JMS, database). Check out the Spring Boot documentation on this. This Spring blog post might also be helpful.

0
Fadi On

The solution to this question is to change the name of the method that returns the transaction manager and defined a qualifier to identify the transaction manager at run time like so :

@Bean
@Qualifier("jmsTransactionManager")
public PlatformTransactionManager jmsTransactionManager() {
    return new JmsTransactionManager(connectionFactory());
}

@Bean
@Primary
@Qualifier("jpaTransactionManager")
public JpaTransactionManager transactionManager() {
    JpaTransactionManager manager = new JpaTransactionManager();
    return manager;
}

and in the service class I have specified which transaction manager to use for the method like so :

@Service
@Transactional(isolation = Isolation.READ_COMMITTED, value="jpaTransactionManager")
public class ImageService implements ImgService

so spring can pick the correct one at runtime

on the JMS class I did the same

@Autowired
private JmsTemplate jmsTemplate;

@Transactional("jmsTransactionManager")
public void send(Image image){
jmsTemplate.convertAndSend(IMAGE_QUEUE,image);
}