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");
}
...
}
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!