javaspring-bootwebsphere-liberty

Spring Boot and WAS Liberty Transaction manager - TransactionSuspensionNotSupportedException


I have deployed Spring Boot application on WAS Liberty. The application has JMS and JDBC operations that have to happen in same transaction. But part of the application needs new "isolated" transaction. I have added @Transactional(propagation = Propagation.REQUIRES_NEW) annotation on the method but it throws TransactionSuspensionNotSupportedException.

The following features are enabled in server.xml

  <featureManager>
    <feature>localConnector-1.0</feature>
    <feature>servlet-6.0</feature>
    <feature>pages-3.1</feature>
    <feature>xmlBinding-4.0</feature>
    <feature>persistence-3.1</feature>
    <feature>messagingClient-3.0</feature>
    <feature>messagingServer-3.0</feature>
    <feature>appSecurity-5.0</feature>
    <feature>restConnector-2.0</feature>
  </featureManager>

Any advice on how to enable transaction suspension or configure TransactionManager in Liberty is greatly appreciated.

Versions:

I tried adding .... but got the following error on startup Caused by: javax.naming.NameNotFoundException: javax.naming.NameNotFoundException: java:comp/TransactionManager

    @Bean
    public JtaTransactionManager transactionManager() throws Exception {
        InitialContext context = new InitialContext();

        UserTransaction utx = (UserTransaction) context.lookup("java:comp/UserTransaction");
        TransactionManager tm = (TransactionManager) context.lookup("java:comp/TransactionManager");

        return new JtaTransactionManager(utx, tm);
    }

Solution

  • I found a working solution. Liberty 23.x does not expose TransactionManager over JNDI, you need to use reflection to obtain TransactionManager.

    This bean definition helped me configure JtaTransactionManager.

        @Bean
        public JtaTransactionManager transactionManager() throws Exception {
            InitialContext context = new InitialContext();
    
            UserTransaction utx = (UserTransaction) context.lookup("java:comp/UserTransaction");
    
            TransactionManager ibmTm = (TransactionManager) Class
                .forName("com.ibm.tx.jta.TransactionManagerFactory")
                .getDeclaredMethod("getTransactionManager")
                .invoke(null);
    
            return new JtaTransactionManager(utx, ibmTm);
        }
    

    I found the answer here: https://stackoverflow.com/a/79363034/30908754