es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

No se encontró el administrador de transacciones predeterminado de Spring al utilizar JmsTransactionManager.

Tengo una aplicación Spring Boot, donde uso JMS con una base de datos. Estoy tratando de configurar JmsTransactionManager para utilizarlo con el TransactionManager por defecto (para JPA). He definido el bean en el archivo @SpringBootApplication (eso significa que tiene @Configuration y @EnableTransactionManagement):

@Bean(name="jmsTransactionManager")
public JmsTransactionManager jmsTransactionManager(ConnectionFactory connectionFactory) {
  JmsTransactionManager jmsTransactionManager = new JmsTransactionManager();
  jmsTransactionManager.setConnectionFactory(connectionFactory);
  return jmsTransactionManager;
}

Ese es el único bean que configuro manualmente para JMS porque otras configuraciones las realiza automáticamente spring-boot, solo tengo propiedades en application.yaml, así que asumo que connectionFactory se autowireará. Y quiero usarlo de la siguiente manera:

@Transactional(transactionManager = "jmsTransactionManager", propagation = Propagation.REQUIRES_NEW)
void do(){
 sendJms();
 saveDb();
}

@Transactional // utiliza el TransactionManager por defecto de JPA
void sendDb(){
 ...
}

La lógica es que primero enviaré al JMS y luego guardaré algo en la base de datos, por lo que necesito dos transacciones separadas, pero quiero cerrar la transacción de la base de datos antes de la transacción del JMS. Tal vez no sea correcto realizar llamadas así en esta situación, pero no sé cómo hacerlo de otra manera utilizando la gestión de transacciones declarativa. Y el problema es que cuando estoy definiendo JmsTransactionManagement, el TransactionManager por defecto, que funciona con la base de datos, deja de funcionar, pero sin JmsTransactionManagement, las transacciones a la base de datos funcionan correctamente:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'transactionManager' available: No matching TransactionManager bean found for qualifier 'transactionManager' - neither qualifier match nor bean name match!

¿Me estoy perdiendo algo? Tengo spring-data-jpa en el POM, por lo que el transactionManager por defecto se configura mediante spring boot, pero no puede encontrarlo, ¿por qué? Desafortunadamente, no encontré la respuesta sobre cómo hacer algo así en StackOverflow.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Parece que estás tratando de utilizar tanto transacciones JMS como JPA en tu aplicación de Spring Boot, pero tienes problemas con la configuración.

    Según el mensaje de error que proporcionaste, parece que el TransactionManager por defecto para JPA no está siendo reconocido cuando defines el bean JmsTransactionManager.

    Una posible solución para este problema es definir explícitamente el bean TransactionManager por defecto en tu configuración, además de definir el bean JmsTransactionManager.

    Aquí tienes un ejemplo de cómo puedes definir ambos beans TransactionManager en la configuración de tu aplicación:

    @Configuration
    @EnableTransactionManagement
    public class AppConfig {

    @Bean(name="transactionManager")
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    }
    
    @Bean(name="jmsTransactionManager")
    public JmsTransactionManager jmsTransactionManager(ConnectionFactory connectionFactory) {
        JmsTransactionManager jmsTransactionManager = new JmsTransactionManager();
        jmsTransactionManager.setConnectionFactory(connectionFactory);
        return jmsTransactionManager;
    }
    

    }

    En este ejemplo, el bean TransactionManager está definido explícitamente con el nombre “transactionManager” (que coincide con el qualifier por defecto utilizado por Spring Boot para transacciones JPA). Esto debería permitir que Spring identifique correctamente el TransactionManager por defecto al utilizar la anotación @Transactional sin ningún qualifier adicional.

    Luego puedes utilizar estos beans TransactionManager en tus métodos de servicio de la siguiente manera:

    @Service
    public class MyService {

    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Autowired
    private JmsTransactionManager jmsTransactionManager;
    
    @Transactional(transactionManager = "jmsTransactionManager", propagation = Propagation.REQUIRES_NEW)
    public void doSomething() {
         // Realizar lógica relacionada con JMS
         sendJms();
    
         // Confirmar transacción JMS
         TransactionStatus jmsTransactionStatus = jmsTransactionManager.getTransaction(null);
         jmsTransactionManager.commit(jmsTransactionStatus);
    
         // Iniciar nueva transacción para lógica relacionada con la base de datos
         TransactionStatus dbTransactionStatus = transactionManager.getTransaction(null);
    
         // Realizar lógica relacionada con la base de datos
         saveDb();
    
         // Confirmar transacción de la base de datos
         transactionManager.commit(dbTransactionStatus);
    }
    

    }

    En este ejemplo, doSomething() está anotado con @Transactional y especifica explícitamente el TransactionManager “jmsTransactionManager” para la lógica relacionada con JMS. Después de enviar el mensaje JMS, la transacción JMS se confirma utilizando el bean JmsTransactionManager. Luego se inicia una nueva transacción (utilizando el TransactionManager por defecto) para la lógica relacionada con la base de datos, y se confirma después de que el método saveDb() se completa.

    Ten en cuenta que este enfoque puede no ser el más adecuado para todos los escenarios, y puede que desees considerar otras alternativas como transacciones programáticas o el uso de un TransactionManager diferente que admita varios tipos de recursos.

Comments are closed.