Bitronix - JMS and JDBC - Message is dequeued on Exception












0















I'm trying to integrate Bitronix Transaction Manager in my Spring boot project to manage jdbc and jms transaction together. I have two databases and one ActiveMQ broker for jms. I've got connect the databases in the same transaction but when I tried to include JMS, It seems not to work.



This is my Bitronix Transaction Manager configuration:



@Configuration
@EnableTransactionManagement
public class BitronixJtaConfiguration {

private static final Logger log = LoggerFactory.getLogger(BitronixJtaConfiguration.class);

@Value("${bitronix.tm.serverId}")
private String serverId;

@Value("${bitronix.tm.journal.disk.logPart1Filename:}")
private String logPart1Filename;

@Value("${bitronix.tm.journal.disk.logPart2Filename:}")
private String logPart2Filename;

@Bean
public bitronix.tm.Configuration transactionManagerServices() {
bitronix.tm.Configuration configuration = TransactionManagerServices.getConfiguration();
configuration.setServerId(serverId);
if ("".equals(logPart1Filename) && "".equals(logPart2Filename)) {
configuration.setJournal(null);
log.info("Disable journal for testing.");
} else {
configuration.setLogPart1Filename(logPart1Filename);
configuration.setLogPart2Filename(logPart2Filename);
}
return configuration;
}

@Bean
public TransactionManager transactionManager() {
return TransactionManagerServices.getTransactionManager();
}

@Bean
public UserTransaction userTransaction() {
return TransactionManagerServices.getTransactionManager();
}

@Bean
public PlatformTransactionManager platformTransactionManager() {
UserTransaction userTransaction = userTransaction();
TransactionManager transactionManager = transactionManager();
return new JtaTransactionManager(userTransaction, transactionManager);
}
}


This is one of my database configuration class:



@Configuration
@EnableTransactionManagement
public class TransportationPlanDBConfig {

private static final Logger LOGGER = LoggerFactory.getLogger("ppalfile");

@Value("${tp.jdbc.driverClassName}")
private String driverClassName;

@Value("${tp.jdbc.username}")
private String username;

@Value("${tp.jdbc.url}")
private String url;

@Value("${tp.jdbc.password}")
private String password;

@Value("${tp.c3p0.max_size}")
private int c3p0MaxSize;

@Value("${tp.c3p0.min_size}")
private int c3p0MinSize;

@Value("${tp.c3p0.unreturned_connection_timeout}")
private int c3p0UnreturnedConnectionTimeout;

@Value("${tp.c3p0.acquire_increment}")
private int c3p0AcquireIncrement;

@Value("${tp.c3p0.max_idle_time}")
private int c3p0MaxIdleTime;

public TransportationPlanDBConfig() {
// Empty constructor
}

@Bean(name = "tpds", destroyMethod = "close")
public DataSource dataSource() {
LOGGER.debug("Creating Transportation plan DS");
PoolingDataSource poolingDataSource = new PoolingDataSource();
poolingDataSource.setClassName(driverClassName);
poolingDataSource.setUniqueName("tpds");
Properties props = new Properties();
props.put("url", url);
props.put("user", username);
props.put("password", password);
poolingDataSource.setDriverProperties(props);
poolingDataSource.setAllowLocalTransactions(true);
poolingDataSource.setMaxPoolSize(c3p0MaxSize);
poolingDataSource.init();
return poolingDataSource;
}

@Bean(name = "tpJdbcTemplate")
JdbcTemplate jdbcTemplate(@Qualifier("tpds") DataSource dataSource) {
LOGGER.debug("Creating JdbcTemplate transport plan");
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
LOGGER.debug(" JdbcTemplate Transport Plan created ");
return jdbcTemplate;
}

}


My ActiveMQ configuration class:



@Configuration
@EnableTransactionManagement
public class ActivesMQsConfiguration {

@Bean
public ConnectionFactory jmsConnectionFactoryLocal() {
PoolingConnectionFactory btmPoolingConnectionFactory = new PoolingConnectionFactory();
btmPoolingConnectionFactory.setClassName("org.apache.activemq.ActiveMQXAConnectionFactory");
btmPoolingConnectionFactory.setUniqueName("AMQLocal");
btmPoolingConnectionFactory.setMinPoolSize(1);
btmPoolingConnectionFactory.setMaxPoolSize(5);
btmPoolingConnectionFactory.setAllowLocalTransactions(true);
btmPoolingConnectionFactory.setUser("admin");
btmPoolingConnectionFactory.setPassword("admin");
btmPoolingConnectionFactory.getDriverProperties().setProperty("brokerURL", "tcp://localhost:61616");
btmPoolingConnectionFactory.init();
return btmPoolingConnectionFactory;
}



@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactoryLocal(
@Qualifier("jmsConnectionFactoryLocal") ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setSessionTransacted(true);
configurer.configure(factory, connectionFactory);
return factory;
}

}


My JMS Listener implemetation:



@Component
@Transactional
public class ContactTransactionReceiver {


private int mensajesConsumer2 = 0;

@Autowired
@Qualifier("versionJdbcTemplate")
private JdbcTemplate versionJdbcTemplate;

@Autowired
@Qualifier("tpJdbcTemplate")
private JdbcTemplate tpjdbcTemplate;

@Autowired
private VersionsConfDao versionsConfDao;

@Autowired
private TrainDao trainDao;


@Transactional(rollbackFor=Exception.class)
@JmsListener(destination = "Consumer.consumer2.VirtualTopic.TopicPrueba")
public void receiveMessageFromContacts2(Message message) throws Exception {
mensajesConsumer2++;
TextMessage txtMessage = (TextMessage) message;
System.out.println("Segundo consumer:" + txtMessage.getText() + " recibidos:" + mensajesConsumer2);


VersionsConf versionsconf = new VersionsConf("V" + mensajesConsumer2, "V" + mensajesConsumer2, false,new Timestamp(1L), 1);
VersionsConf versionsResult = versionsConfDao.insertUpdate(versionJdbcTemplate, versionsconf);

if (mensajesConsumer2 == 2) {
throw new Exception();
}

Train train = new Train("101"+mensajesConsumer2, 1L, 2L, false, true, "atp");
Train trainResult = trainDao.insertUpdate(tpjdbcTemplate, train);

if (mensajesConsumer2 == 3) {
throw new Exception();
}
}

}


Based on my listener implementation, as I understood Bitronix functionality:




  1. On first incoming message: Must insert one row in each database and dequeue the message. -> This works fine.


  2. On second and third incoming message: Must insert 0 rows due to the exception and keep the message in the queue. -> No rows inserted but the message is dequeued.



Moreover, I'd like to add that It logs the following during the execution:
[main] bitronix.tm.recovery.Recoverer: recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 4 resource(s) [AMQLocal, vds, AMQRemote, tpds]



So, I understood that both brokers and both data bases are registered. But when the listener process the second message (It throws an exception), and It logs:



WARN 5740 [Session Task-1] bitronix.tm.twopc.Preparer : executing transaction with 0 enlisted resource



Any idea about the problem??



You can find the full code on: https://github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git



Thanks!










share|improve this question





























    0















    I'm trying to integrate Bitronix Transaction Manager in my Spring boot project to manage jdbc and jms transaction together. I have two databases and one ActiveMQ broker for jms. I've got connect the databases in the same transaction but when I tried to include JMS, It seems not to work.



    This is my Bitronix Transaction Manager configuration:



    @Configuration
    @EnableTransactionManagement
    public class BitronixJtaConfiguration {

    private static final Logger log = LoggerFactory.getLogger(BitronixJtaConfiguration.class);

    @Value("${bitronix.tm.serverId}")
    private String serverId;

    @Value("${bitronix.tm.journal.disk.logPart1Filename:}")
    private String logPart1Filename;

    @Value("${bitronix.tm.journal.disk.logPart2Filename:}")
    private String logPart2Filename;

    @Bean
    public bitronix.tm.Configuration transactionManagerServices() {
    bitronix.tm.Configuration configuration = TransactionManagerServices.getConfiguration();
    configuration.setServerId(serverId);
    if ("".equals(logPart1Filename) && "".equals(logPart2Filename)) {
    configuration.setJournal(null);
    log.info("Disable journal for testing.");
    } else {
    configuration.setLogPart1Filename(logPart1Filename);
    configuration.setLogPart2Filename(logPart2Filename);
    }
    return configuration;
    }

    @Bean
    public TransactionManager transactionManager() {
    return TransactionManagerServices.getTransactionManager();
    }

    @Bean
    public UserTransaction userTransaction() {
    return TransactionManagerServices.getTransactionManager();
    }

    @Bean
    public PlatformTransactionManager platformTransactionManager() {
    UserTransaction userTransaction = userTransaction();
    TransactionManager transactionManager = transactionManager();
    return new JtaTransactionManager(userTransaction, transactionManager);
    }
    }


    This is one of my database configuration class:



    @Configuration
    @EnableTransactionManagement
    public class TransportationPlanDBConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger("ppalfile");

    @Value("${tp.jdbc.driverClassName}")
    private String driverClassName;

    @Value("${tp.jdbc.username}")
    private String username;

    @Value("${tp.jdbc.url}")
    private String url;

    @Value("${tp.jdbc.password}")
    private String password;

    @Value("${tp.c3p0.max_size}")
    private int c3p0MaxSize;

    @Value("${tp.c3p0.min_size}")
    private int c3p0MinSize;

    @Value("${tp.c3p0.unreturned_connection_timeout}")
    private int c3p0UnreturnedConnectionTimeout;

    @Value("${tp.c3p0.acquire_increment}")
    private int c3p0AcquireIncrement;

    @Value("${tp.c3p0.max_idle_time}")
    private int c3p0MaxIdleTime;

    public TransportationPlanDBConfig() {
    // Empty constructor
    }

    @Bean(name = "tpds", destroyMethod = "close")
    public DataSource dataSource() {
    LOGGER.debug("Creating Transportation plan DS");
    PoolingDataSource poolingDataSource = new PoolingDataSource();
    poolingDataSource.setClassName(driverClassName);
    poolingDataSource.setUniqueName("tpds");
    Properties props = new Properties();
    props.put("url", url);
    props.put("user", username);
    props.put("password", password);
    poolingDataSource.setDriverProperties(props);
    poolingDataSource.setAllowLocalTransactions(true);
    poolingDataSource.setMaxPoolSize(c3p0MaxSize);
    poolingDataSource.init();
    return poolingDataSource;
    }

    @Bean(name = "tpJdbcTemplate")
    JdbcTemplate jdbcTemplate(@Qualifier("tpds") DataSource dataSource) {
    LOGGER.debug("Creating JdbcTemplate transport plan");
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    LOGGER.debug(" JdbcTemplate Transport Plan created ");
    return jdbcTemplate;
    }

    }


    My ActiveMQ configuration class:



    @Configuration
    @EnableTransactionManagement
    public class ActivesMQsConfiguration {

    @Bean
    public ConnectionFactory jmsConnectionFactoryLocal() {
    PoolingConnectionFactory btmPoolingConnectionFactory = new PoolingConnectionFactory();
    btmPoolingConnectionFactory.setClassName("org.apache.activemq.ActiveMQXAConnectionFactory");
    btmPoolingConnectionFactory.setUniqueName("AMQLocal");
    btmPoolingConnectionFactory.setMinPoolSize(1);
    btmPoolingConnectionFactory.setMaxPoolSize(5);
    btmPoolingConnectionFactory.setAllowLocalTransactions(true);
    btmPoolingConnectionFactory.setUser("admin");
    btmPoolingConnectionFactory.setPassword("admin");
    btmPoolingConnectionFactory.getDriverProperties().setProperty("brokerURL", "tcp://localhost:61616");
    btmPoolingConnectionFactory.init();
    return btmPoolingConnectionFactory;
    }



    @Bean
    public JmsListenerContainerFactory<?> jmsListenerContainerFactoryLocal(
    @Qualifier("jmsConnectionFactoryLocal") ConnectionFactory connectionFactory,
    DefaultJmsListenerContainerFactoryConfigurer configurer) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setSessionTransacted(true);
    configurer.configure(factory, connectionFactory);
    return factory;
    }

    }


    My JMS Listener implemetation:



    @Component
    @Transactional
    public class ContactTransactionReceiver {


    private int mensajesConsumer2 = 0;

    @Autowired
    @Qualifier("versionJdbcTemplate")
    private JdbcTemplate versionJdbcTemplate;

    @Autowired
    @Qualifier("tpJdbcTemplate")
    private JdbcTemplate tpjdbcTemplate;

    @Autowired
    private VersionsConfDao versionsConfDao;

    @Autowired
    private TrainDao trainDao;


    @Transactional(rollbackFor=Exception.class)
    @JmsListener(destination = "Consumer.consumer2.VirtualTopic.TopicPrueba")
    public void receiveMessageFromContacts2(Message message) throws Exception {
    mensajesConsumer2++;
    TextMessage txtMessage = (TextMessage) message;
    System.out.println("Segundo consumer:" + txtMessage.getText() + " recibidos:" + mensajesConsumer2);


    VersionsConf versionsconf = new VersionsConf("V" + mensajesConsumer2, "V" + mensajesConsumer2, false,new Timestamp(1L), 1);
    VersionsConf versionsResult = versionsConfDao.insertUpdate(versionJdbcTemplate, versionsconf);

    if (mensajesConsumer2 == 2) {
    throw new Exception();
    }

    Train train = new Train("101"+mensajesConsumer2, 1L, 2L, false, true, "atp");
    Train trainResult = trainDao.insertUpdate(tpjdbcTemplate, train);

    if (mensajesConsumer2 == 3) {
    throw new Exception();
    }
    }

    }


    Based on my listener implementation, as I understood Bitronix functionality:




    1. On first incoming message: Must insert one row in each database and dequeue the message. -> This works fine.


    2. On second and third incoming message: Must insert 0 rows due to the exception and keep the message in the queue. -> No rows inserted but the message is dequeued.



    Moreover, I'd like to add that It logs the following during the execution:
    [main] bitronix.tm.recovery.Recoverer: recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 4 resource(s) [AMQLocal, vds, AMQRemote, tpds]



    So, I understood that both brokers and both data bases are registered. But when the listener process the second message (It throws an exception), and It logs:



    WARN 5740 [Session Task-1] bitronix.tm.twopc.Preparer : executing transaction with 0 enlisted resource



    Any idea about the problem??



    You can find the full code on: https://github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git



    Thanks!










    share|improve this question



























      0












      0








      0








      I'm trying to integrate Bitronix Transaction Manager in my Spring boot project to manage jdbc and jms transaction together. I have two databases and one ActiveMQ broker for jms. I've got connect the databases in the same transaction but when I tried to include JMS, It seems not to work.



      This is my Bitronix Transaction Manager configuration:



      @Configuration
      @EnableTransactionManagement
      public class BitronixJtaConfiguration {

      private static final Logger log = LoggerFactory.getLogger(BitronixJtaConfiguration.class);

      @Value("${bitronix.tm.serverId}")
      private String serverId;

      @Value("${bitronix.tm.journal.disk.logPart1Filename:}")
      private String logPart1Filename;

      @Value("${bitronix.tm.journal.disk.logPart2Filename:}")
      private String logPart2Filename;

      @Bean
      public bitronix.tm.Configuration transactionManagerServices() {
      bitronix.tm.Configuration configuration = TransactionManagerServices.getConfiguration();
      configuration.setServerId(serverId);
      if ("".equals(logPart1Filename) && "".equals(logPart2Filename)) {
      configuration.setJournal(null);
      log.info("Disable journal for testing.");
      } else {
      configuration.setLogPart1Filename(logPart1Filename);
      configuration.setLogPart2Filename(logPart2Filename);
      }
      return configuration;
      }

      @Bean
      public TransactionManager transactionManager() {
      return TransactionManagerServices.getTransactionManager();
      }

      @Bean
      public UserTransaction userTransaction() {
      return TransactionManagerServices.getTransactionManager();
      }

      @Bean
      public PlatformTransactionManager platformTransactionManager() {
      UserTransaction userTransaction = userTransaction();
      TransactionManager transactionManager = transactionManager();
      return new JtaTransactionManager(userTransaction, transactionManager);
      }
      }


      This is one of my database configuration class:



      @Configuration
      @EnableTransactionManagement
      public class TransportationPlanDBConfig {

      private static final Logger LOGGER = LoggerFactory.getLogger("ppalfile");

      @Value("${tp.jdbc.driverClassName}")
      private String driverClassName;

      @Value("${tp.jdbc.username}")
      private String username;

      @Value("${tp.jdbc.url}")
      private String url;

      @Value("${tp.jdbc.password}")
      private String password;

      @Value("${tp.c3p0.max_size}")
      private int c3p0MaxSize;

      @Value("${tp.c3p0.min_size}")
      private int c3p0MinSize;

      @Value("${tp.c3p0.unreturned_connection_timeout}")
      private int c3p0UnreturnedConnectionTimeout;

      @Value("${tp.c3p0.acquire_increment}")
      private int c3p0AcquireIncrement;

      @Value("${tp.c3p0.max_idle_time}")
      private int c3p0MaxIdleTime;

      public TransportationPlanDBConfig() {
      // Empty constructor
      }

      @Bean(name = "tpds", destroyMethod = "close")
      public DataSource dataSource() {
      LOGGER.debug("Creating Transportation plan DS");
      PoolingDataSource poolingDataSource = new PoolingDataSource();
      poolingDataSource.setClassName(driverClassName);
      poolingDataSource.setUniqueName("tpds");
      Properties props = new Properties();
      props.put("url", url);
      props.put("user", username);
      props.put("password", password);
      poolingDataSource.setDriverProperties(props);
      poolingDataSource.setAllowLocalTransactions(true);
      poolingDataSource.setMaxPoolSize(c3p0MaxSize);
      poolingDataSource.init();
      return poolingDataSource;
      }

      @Bean(name = "tpJdbcTemplate")
      JdbcTemplate jdbcTemplate(@Qualifier("tpds") DataSource dataSource) {
      LOGGER.debug("Creating JdbcTemplate transport plan");
      JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
      LOGGER.debug(" JdbcTemplate Transport Plan created ");
      return jdbcTemplate;
      }

      }


      My ActiveMQ configuration class:



      @Configuration
      @EnableTransactionManagement
      public class ActivesMQsConfiguration {

      @Bean
      public ConnectionFactory jmsConnectionFactoryLocal() {
      PoolingConnectionFactory btmPoolingConnectionFactory = new PoolingConnectionFactory();
      btmPoolingConnectionFactory.setClassName("org.apache.activemq.ActiveMQXAConnectionFactory");
      btmPoolingConnectionFactory.setUniqueName("AMQLocal");
      btmPoolingConnectionFactory.setMinPoolSize(1);
      btmPoolingConnectionFactory.setMaxPoolSize(5);
      btmPoolingConnectionFactory.setAllowLocalTransactions(true);
      btmPoolingConnectionFactory.setUser("admin");
      btmPoolingConnectionFactory.setPassword("admin");
      btmPoolingConnectionFactory.getDriverProperties().setProperty("brokerURL", "tcp://localhost:61616");
      btmPoolingConnectionFactory.init();
      return btmPoolingConnectionFactory;
      }



      @Bean
      public JmsListenerContainerFactory<?> jmsListenerContainerFactoryLocal(
      @Qualifier("jmsConnectionFactoryLocal") ConnectionFactory connectionFactory,
      DefaultJmsListenerContainerFactoryConfigurer configurer) {
      DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
      factory.setConnectionFactory(connectionFactory);
      factory.setSessionTransacted(true);
      configurer.configure(factory, connectionFactory);
      return factory;
      }

      }


      My JMS Listener implemetation:



      @Component
      @Transactional
      public class ContactTransactionReceiver {


      private int mensajesConsumer2 = 0;

      @Autowired
      @Qualifier("versionJdbcTemplate")
      private JdbcTemplate versionJdbcTemplate;

      @Autowired
      @Qualifier("tpJdbcTemplate")
      private JdbcTemplate tpjdbcTemplate;

      @Autowired
      private VersionsConfDao versionsConfDao;

      @Autowired
      private TrainDao trainDao;


      @Transactional(rollbackFor=Exception.class)
      @JmsListener(destination = "Consumer.consumer2.VirtualTopic.TopicPrueba")
      public void receiveMessageFromContacts2(Message message) throws Exception {
      mensajesConsumer2++;
      TextMessage txtMessage = (TextMessage) message;
      System.out.println("Segundo consumer:" + txtMessage.getText() + " recibidos:" + mensajesConsumer2);


      VersionsConf versionsconf = new VersionsConf("V" + mensajesConsumer2, "V" + mensajesConsumer2, false,new Timestamp(1L), 1);
      VersionsConf versionsResult = versionsConfDao.insertUpdate(versionJdbcTemplate, versionsconf);

      if (mensajesConsumer2 == 2) {
      throw new Exception();
      }

      Train train = new Train("101"+mensajesConsumer2, 1L, 2L, false, true, "atp");
      Train trainResult = trainDao.insertUpdate(tpjdbcTemplate, train);

      if (mensajesConsumer2 == 3) {
      throw new Exception();
      }
      }

      }


      Based on my listener implementation, as I understood Bitronix functionality:




      1. On first incoming message: Must insert one row in each database and dequeue the message. -> This works fine.


      2. On second and third incoming message: Must insert 0 rows due to the exception and keep the message in the queue. -> No rows inserted but the message is dequeued.



      Moreover, I'd like to add that It logs the following during the execution:
      [main] bitronix.tm.recovery.Recoverer: recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 4 resource(s) [AMQLocal, vds, AMQRemote, tpds]



      So, I understood that both brokers and both data bases are registered. But when the listener process the second message (It throws an exception), and It logs:



      WARN 5740 [Session Task-1] bitronix.tm.twopc.Preparer : executing transaction with 0 enlisted resource



      Any idea about the problem??



      You can find the full code on: https://github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git



      Thanks!










      share|improve this question
















      I'm trying to integrate Bitronix Transaction Manager in my Spring boot project to manage jdbc and jms transaction together. I have two databases and one ActiveMQ broker for jms. I've got connect the databases in the same transaction but when I tried to include JMS, It seems not to work.



      This is my Bitronix Transaction Manager configuration:



      @Configuration
      @EnableTransactionManagement
      public class BitronixJtaConfiguration {

      private static final Logger log = LoggerFactory.getLogger(BitronixJtaConfiguration.class);

      @Value("${bitronix.tm.serverId}")
      private String serverId;

      @Value("${bitronix.tm.journal.disk.logPart1Filename:}")
      private String logPart1Filename;

      @Value("${bitronix.tm.journal.disk.logPart2Filename:}")
      private String logPart2Filename;

      @Bean
      public bitronix.tm.Configuration transactionManagerServices() {
      bitronix.tm.Configuration configuration = TransactionManagerServices.getConfiguration();
      configuration.setServerId(serverId);
      if ("".equals(logPart1Filename) && "".equals(logPart2Filename)) {
      configuration.setJournal(null);
      log.info("Disable journal for testing.");
      } else {
      configuration.setLogPart1Filename(logPart1Filename);
      configuration.setLogPart2Filename(logPart2Filename);
      }
      return configuration;
      }

      @Bean
      public TransactionManager transactionManager() {
      return TransactionManagerServices.getTransactionManager();
      }

      @Bean
      public UserTransaction userTransaction() {
      return TransactionManagerServices.getTransactionManager();
      }

      @Bean
      public PlatformTransactionManager platformTransactionManager() {
      UserTransaction userTransaction = userTransaction();
      TransactionManager transactionManager = transactionManager();
      return new JtaTransactionManager(userTransaction, transactionManager);
      }
      }


      This is one of my database configuration class:



      @Configuration
      @EnableTransactionManagement
      public class TransportationPlanDBConfig {

      private static final Logger LOGGER = LoggerFactory.getLogger("ppalfile");

      @Value("${tp.jdbc.driverClassName}")
      private String driverClassName;

      @Value("${tp.jdbc.username}")
      private String username;

      @Value("${tp.jdbc.url}")
      private String url;

      @Value("${tp.jdbc.password}")
      private String password;

      @Value("${tp.c3p0.max_size}")
      private int c3p0MaxSize;

      @Value("${tp.c3p0.min_size}")
      private int c3p0MinSize;

      @Value("${tp.c3p0.unreturned_connection_timeout}")
      private int c3p0UnreturnedConnectionTimeout;

      @Value("${tp.c3p0.acquire_increment}")
      private int c3p0AcquireIncrement;

      @Value("${tp.c3p0.max_idle_time}")
      private int c3p0MaxIdleTime;

      public TransportationPlanDBConfig() {
      // Empty constructor
      }

      @Bean(name = "tpds", destroyMethod = "close")
      public DataSource dataSource() {
      LOGGER.debug("Creating Transportation plan DS");
      PoolingDataSource poolingDataSource = new PoolingDataSource();
      poolingDataSource.setClassName(driverClassName);
      poolingDataSource.setUniqueName("tpds");
      Properties props = new Properties();
      props.put("url", url);
      props.put("user", username);
      props.put("password", password);
      poolingDataSource.setDriverProperties(props);
      poolingDataSource.setAllowLocalTransactions(true);
      poolingDataSource.setMaxPoolSize(c3p0MaxSize);
      poolingDataSource.init();
      return poolingDataSource;
      }

      @Bean(name = "tpJdbcTemplate")
      JdbcTemplate jdbcTemplate(@Qualifier("tpds") DataSource dataSource) {
      LOGGER.debug("Creating JdbcTemplate transport plan");
      JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
      LOGGER.debug(" JdbcTemplate Transport Plan created ");
      return jdbcTemplate;
      }

      }


      My ActiveMQ configuration class:



      @Configuration
      @EnableTransactionManagement
      public class ActivesMQsConfiguration {

      @Bean
      public ConnectionFactory jmsConnectionFactoryLocal() {
      PoolingConnectionFactory btmPoolingConnectionFactory = new PoolingConnectionFactory();
      btmPoolingConnectionFactory.setClassName("org.apache.activemq.ActiveMQXAConnectionFactory");
      btmPoolingConnectionFactory.setUniqueName("AMQLocal");
      btmPoolingConnectionFactory.setMinPoolSize(1);
      btmPoolingConnectionFactory.setMaxPoolSize(5);
      btmPoolingConnectionFactory.setAllowLocalTransactions(true);
      btmPoolingConnectionFactory.setUser("admin");
      btmPoolingConnectionFactory.setPassword("admin");
      btmPoolingConnectionFactory.getDriverProperties().setProperty("brokerURL", "tcp://localhost:61616");
      btmPoolingConnectionFactory.init();
      return btmPoolingConnectionFactory;
      }



      @Bean
      public JmsListenerContainerFactory<?> jmsListenerContainerFactoryLocal(
      @Qualifier("jmsConnectionFactoryLocal") ConnectionFactory connectionFactory,
      DefaultJmsListenerContainerFactoryConfigurer configurer) {
      DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
      factory.setConnectionFactory(connectionFactory);
      factory.setSessionTransacted(true);
      configurer.configure(factory, connectionFactory);
      return factory;
      }

      }


      My JMS Listener implemetation:



      @Component
      @Transactional
      public class ContactTransactionReceiver {


      private int mensajesConsumer2 = 0;

      @Autowired
      @Qualifier("versionJdbcTemplate")
      private JdbcTemplate versionJdbcTemplate;

      @Autowired
      @Qualifier("tpJdbcTemplate")
      private JdbcTemplate tpjdbcTemplate;

      @Autowired
      private VersionsConfDao versionsConfDao;

      @Autowired
      private TrainDao trainDao;


      @Transactional(rollbackFor=Exception.class)
      @JmsListener(destination = "Consumer.consumer2.VirtualTopic.TopicPrueba")
      public void receiveMessageFromContacts2(Message message) throws Exception {
      mensajesConsumer2++;
      TextMessage txtMessage = (TextMessage) message;
      System.out.println("Segundo consumer:" + txtMessage.getText() + " recibidos:" + mensajesConsumer2);


      VersionsConf versionsconf = new VersionsConf("V" + mensajesConsumer2, "V" + mensajesConsumer2, false,new Timestamp(1L), 1);
      VersionsConf versionsResult = versionsConfDao.insertUpdate(versionJdbcTemplate, versionsconf);

      if (mensajesConsumer2 == 2) {
      throw new Exception();
      }

      Train train = new Train("101"+mensajesConsumer2, 1L, 2L, false, true, "atp");
      Train trainResult = trainDao.insertUpdate(tpjdbcTemplate, train);

      if (mensajesConsumer2 == 3) {
      throw new Exception();
      }
      }

      }


      Based on my listener implementation, as I understood Bitronix functionality:




      1. On first incoming message: Must insert one row in each database and dequeue the message. -> This works fine.


      2. On second and third incoming message: Must insert 0 rows due to the exception and keep the message in the queue. -> No rows inserted but the message is dequeued.



      Moreover, I'd like to add that It logs the following during the execution:
      [main] bitronix.tm.recovery.Recoverer: recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 4 resource(s) [AMQLocal, vds, AMQRemote, tpds]



      So, I understood that both brokers and both data bases are registered. But when the listener process the second message (It throws an exception), and It logs:



      WARN 5740 [Session Task-1] bitronix.tm.twopc.Preparer : executing transaction with 0 enlisted resource



      Any idea about the problem??



      You can find the full code on: https://github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git



      Thanks!







      spring-boot mariadb activemq bitronix






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 27 '18 at 8:54







      Pedro Ramírez Pérez

















      asked Nov 26 '18 at 11:01









      Pedro Ramírez PérezPedro Ramírez Pérez

      105




      105
























          1 Answer
          1






          active

          oldest

          votes


















          0














          First, the recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 4 resource(s) message is going to appear every now and then and it is perfectly normal. You can ignore it as long as the committed and rolled back counters are at zero.



          The executing transaction with 0 enlisted resource log looks like the real deal.



          I highly suspect a problem with your Spring setup. I'm no Spring expert by any mean, but the DefaultJmsListenerContainerFactory should have a reference to your Spring PlatformTransactionManager instance, so that it knows it has to work transactionally, so you should call factory.setTransactionManager(PlatformTransactionManager).



          This should at least move you to the next step.






          share|improve this answer
























          • Thank you very much Ludovic! You were right! Finally, I decided to delete BitronixJtaConfiguration and use embeded Spring's transaction manager because It didn't allow me to modify the listener factory in that way. If someone is interested in the solution It could be found in: github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git

            – Pedro Ramírez Pérez
            Nov 27 '18 at 10:33











          • Your github link reaches a 404.

            – Ludovic Orban
            Nov 27 '18 at 17:24











          • FYI, getting rid of BTM will make your program partially rollback in case of a crash as the transaction manager Spring embeds only implements the happy path, and none of the crash recovery bits.

            – Ludovic Orban
            Nov 27 '18 at 17:26











          • Ok I made a mistake uploading the code. Tomorrow I will upload again. Do you mean for example If data base connection is lost during the transaction the rest of resources included in the transaction would be commited?

            – Pedro Ramírez Pérez
            Nov 27 '18 at 17:33











          • The easiest example I have in mind is if your java process crashes while it is in the middle of the commit.

            – Ludovic Orban
            Nov 27 '18 at 17:37












          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53479717%2fbitronix-jms-and-jdbc-message-is-dequeued-on-exception%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          0














          First, the recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 4 resource(s) message is going to appear every now and then and it is perfectly normal. You can ignore it as long as the committed and rolled back counters are at zero.



          The executing transaction with 0 enlisted resource log looks like the real deal.



          I highly suspect a problem with your Spring setup. I'm no Spring expert by any mean, but the DefaultJmsListenerContainerFactory should have a reference to your Spring PlatformTransactionManager instance, so that it knows it has to work transactionally, so you should call factory.setTransactionManager(PlatformTransactionManager).



          This should at least move you to the next step.






          share|improve this answer
























          • Thank you very much Ludovic! You were right! Finally, I decided to delete BitronixJtaConfiguration and use embeded Spring's transaction manager because It didn't allow me to modify the listener factory in that way. If someone is interested in the solution It could be found in: github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git

            – Pedro Ramírez Pérez
            Nov 27 '18 at 10:33











          • Your github link reaches a 404.

            – Ludovic Orban
            Nov 27 '18 at 17:24











          • FYI, getting rid of BTM will make your program partially rollback in case of a crash as the transaction manager Spring embeds only implements the happy path, and none of the crash recovery bits.

            – Ludovic Orban
            Nov 27 '18 at 17:26











          • Ok I made a mistake uploading the code. Tomorrow I will upload again. Do you mean for example If data base connection is lost during the transaction the rest of resources included in the transaction would be commited?

            – Pedro Ramírez Pérez
            Nov 27 '18 at 17:33











          • The easiest example I have in mind is if your java process crashes while it is in the middle of the commit.

            – Ludovic Orban
            Nov 27 '18 at 17:37
















          0














          First, the recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 4 resource(s) message is going to appear every now and then and it is perfectly normal. You can ignore it as long as the committed and rolled back counters are at zero.



          The executing transaction with 0 enlisted resource log looks like the real deal.



          I highly suspect a problem with your Spring setup. I'm no Spring expert by any mean, but the DefaultJmsListenerContainerFactory should have a reference to your Spring PlatformTransactionManager instance, so that it knows it has to work transactionally, so you should call factory.setTransactionManager(PlatformTransactionManager).



          This should at least move you to the next step.






          share|improve this answer
























          • Thank you very much Ludovic! You were right! Finally, I decided to delete BitronixJtaConfiguration and use embeded Spring's transaction manager because It didn't allow me to modify the listener factory in that way. If someone is interested in the solution It could be found in: github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git

            – Pedro Ramírez Pérez
            Nov 27 '18 at 10:33











          • Your github link reaches a 404.

            – Ludovic Orban
            Nov 27 '18 at 17:24











          • FYI, getting rid of BTM will make your program partially rollback in case of a crash as the transaction manager Spring embeds only implements the happy path, and none of the crash recovery bits.

            – Ludovic Orban
            Nov 27 '18 at 17:26











          • Ok I made a mistake uploading the code. Tomorrow I will upload again. Do you mean for example If data base connection is lost during the transaction the rest of resources included in the transaction would be commited?

            – Pedro Ramírez Pérez
            Nov 27 '18 at 17:33











          • The easiest example I have in mind is if your java process crashes while it is in the middle of the commit.

            – Ludovic Orban
            Nov 27 '18 at 17:37














          0












          0








          0







          First, the recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 4 resource(s) message is going to appear every now and then and it is perfectly normal. You can ignore it as long as the committed and rolled back counters are at zero.



          The executing transaction with 0 enlisted resource log looks like the real deal.



          I highly suspect a problem with your Spring setup. I'm no Spring expert by any mean, but the DefaultJmsListenerContainerFactory should have a reference to your Spring PlatformTransactionManager instance, so that it knows it has to work transactionally, so you should call factory.setTransactionManager(PlatformTransactionManager).



          This should at least move you to the next step.






          share|improve this answer













          First, the recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 4 resource(s) message is going to appear every now and then and it is perfectly normal. You can ignore it as long as the committed and rolled back counters are at zero.



          The executing transaction with 0 enlisted resource log looks like the real deal.



          I highly suspect a problem with your Spring setup. I'm no Spring expert by any mean, but the DefaultJmsListenerContainerFactory should have a reference to your Spring PlatformTransactionManager instance, so that it knows it has to work transactionally, so you should call factory.setTransactionManager(PlatformTransactionManager).



          This should at least move you to the next step.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 27 '18 at 9:18









          Ludovic OrbanLudovic Orban

          34614




          34614













          • Thank you very much Ludovic! You were right! Finally, I decided to delete BitronixJtaConfiguration and use embeded Spring's transaction manager because It didn't allow me to modify the listener factory in that way. If someone is interested in the solution It could be found in: github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git

            – Pedro Ramírez Pérez
            Nov 27 '18 at 10:33











          • Your github link reaches a 404.

            – Ludovic Orban
            Nov 27 '18 at 17:24











          • FYI, getting rid of BTM will make your program partially rollback in case of a crash as the transaction manager Spring embeds only implements the happy path, and none of the crash recovery bits.

            – Ludovic Orban
            Nov 27 '18 at 17:26











          • Ok I made a mistake uploading the code. Tomorrow I will upload again. Do you mean for example If data base connection is lost during the transaction the rest of resources included in the transaction would be commited?

            – Pedro Ramírez Pérez
            Nov 27 '18 at 17:33











          • The easiest example I have in mind is if your java process crashes while it is in the middle of the commit.

            – Ludovic Orban
            Nov 27 '18 at 17:37



















          • Thank you very much Ludovic! You were right! Finally, I decided to delete BitronixJtaConfiguration and use embeded Spring's transaction manager because It didn't allow me to modify the listener factory in that way. If someone is interested in the solution It could be found in: github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git

            – Pedro Ramírez Pérez
            Nov 27 '18 at 10:33











          • Your github link reaches a 404.

            – Ludovic Orban
            Nov 27 '18 at 17:24











          • FYI, getting rid of BTM will make your program partially rollback in case of a crash as the transaction manager Spring embeds only implements the happy path, and none of the crash recovery bits.

            – Ludovic Orban
            Nov 27 '18 at 17:26











          • Ok I made a mistake uploading the code. Tomorrow I will upload again. Do you mean for example If data base connection is lost during the transaction the rest of resources included in the transaction would be commited?

            – Pedro Ramírez Pérez
            Nov 27 '18 at 17:33











          • The easiest example I have in mind is if your java process crashes while it is in the middle of the commit.

            – Ludovic Orban
            Nov 27 '18 at 17:37

















          Thank you very much Ludovic! You were right! Finally, I decided to delete BitronixJtaConfiguration and use embeded Spring's transaction manager because It didn't allow me to modify the listener factory in that way. If someone is interested in the solution It could be found in: github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git

          – Pedro Ramírez Pérez
          Nov 27 '18 at 10:33





          Thank you very much Ludovic! You were right! Finally, I decided to delete BitronixJtaConfiguration and use embeded Spring's transaction manager because It didn't allow me to modify the listener factory in that way. If someone is interested in the solution It could be found in: github.com/PedroRamirezTOR/spring-jms-jdbc-integration.git

          – Pedro Ramírez Pérez
          Nov 27 '18 at 10:33













          Your github link reaches a 404.

          – Ludovic Orban
          Nov 27 '18 at 17:24





          Your github link reaches a 404.

          – Ludovic Orban
          Nov 27 '18 at 17:24













          FYI, getting rid of BTM will make your program partially rollback in case of a crash as the transaction manager Spring embeds only implements the happy path, and none of the crash recovery bits.

          – Ludovic Orban
          Nov 27 '18 at 17:26





          FYI, getting rid of BTM will make your program partially rollback in case of a crash as the transaction manager Spring embeds only implements the happy path, and none of the crash recovery bits.

          – Ludovic Orban
          Nov 27 '18 at 17:26













          Ok I made a mistake uploading the code. Tomorrow I will upload again. Do you mean for example If data base connection is lost during the transaction the rest of resources included in the transaction would be commited?

          – Pedro Ramírez Pérez
          Nov 27 '18 at 17:33





          Ok I made a mistake uploading the code. Tomorrow I will upload again. Do you mean for example If data base connection is lost during the transaction the rest of resources included in the transaction would be commited?

          – Pedro Ramírez Pérez
          Nov 27 '18 at 17:33













          The easiest example I have in mind is if your java process crashes while it is in the middle of the commit.

          – Ludovic Orban
          Nov 27 '18 at 17:37





          The easiest example I have in mind is if your java process crashes while it is in the middle of the commit.

          – Ludovic Orban
          Nov 27 '18 at 17:37




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53479717%2fbitronix-jms-and-jdbc-message-is-dequeued-on-exception%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Wiesbaden

          Marschland

          Dieringhausen