Search code examples
javaspringjax-wsjdbctemplatespring-transactions

Spring transactions not working + JAX WS + JDBC


I'm a bit exasperated with this issue. Lets check if someone has implemented something similar.

I have a java 8 web application with 8 WS implemented. Some of this WS, make inserts and updates through JDBCTemplate (Hibernate is not a choice due to performance needs) and i need them to rollback if execution crashes with an exception.

I have the following configuration of datasource and transaction manager in spring app context file (jndi resource in server.xml/context.xml of Tomcat):

  <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/source" />
  </bean>
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
  </bean>

  <tx:annotation-driven transaction-manager="transactionManager" />

On the other hand I have a unique accesspoint to the dataBase DBcontroller.class, which has a generic method for inserts, deletes and updates:

private NamedParameterJdbcTemplate jdbcTemplate;
private DataSource datasource;

@Autowired
public void setDataSource(DataSource dataSource) {
    this.datasource = dataSource;
    this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
@Override
public boolean queryForModifying(String query, SqlParameterSource parameters) {

  int modifiedRows= 0;
  try {
      modifiedRows= this.jdbcTemplate.update(query, parameters);
  } catch (Exception e) {
      e.printStackTrace();
      numRegistrosAfectados = 0;
  }
  return (modifiedRows> 0) ? true : false;
}

Finally I have a WS Interface This way:

@WebService
public interface IService{

    @WebMethod
    public method(MethodRequestType request) throws IllegalArgumentException, IllegalAccessException;

}

with its implementation:

@WebService(endpointInterface = "com.package.IService")
@HandlerChain(file = "handler-chain.xml")
public class Service implements IService{

    @Autowired
    IDBController dbController;

with a "transactional" method:

@Transactional
private boolean inserts(HashMap<String, Object> input, MethodRequestType request) {.....

It should be working ok on a non WS project, but as I have discovered there is no so easy way for making this work.

First I thought it didn't rollback, but now I'm quite sure it doesn't create transactions.

There are some similar post in stackoverflow, but none of them fix my problem. I have google it a lot, and the only way suggested is WS-AtomicTransactions, which I have never heard about.

I have try almost everything in XML configuration file, I have even tried to manage transactions programatically, but as it is a pool of connections I'm not able to set autocommit to false so that I can force rollbacks.

For if it is useful for anyone, I have soap handlers implemented for each WS, that look this way:

public class ServiceHandler implements SOAPHandler<SOAPMessageContext> {

    private SoapFaultHandler soapFaultHandler;

    @Override
    public boolean handleMessage(SOAPMessageContext context) {

        SOAPMessage message = context.getMessage();
        soapFaultHandler = new SoapFaultHandler(message);
        return SoapMessageHandler.handleMessage(context, "Service name", logger);
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return soapFaultHandler.handleFault(context, logger, "ServiceName");

    }
    ...
}

Solution

  • Finally I have found the way! I was really close allways:

    • The transactional method (as Gavi said) must be public ( but that was not the problem, cause I tried it before).

    • The transactional method should be in other class, not in the Webservice annotated class.

    • This class needs to be autowired so that it is in the Spring context.

    • In this class I have autowired a DbController instance.

    And that was everything.

    My main problem, was that I mocked this class and instantiated it with a "new", instead letting Spring makes its magic.

    Thanks for responses, hope to help others!