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");
}
...
}
It loops through the list of people and, for each person, inserts that person into the BOOKINGS table by using the JdbcTemplate . This method is tagged with @Transactional , meaning that any failure causes the entire operation to roll back to its previous state and to re-throw the original exception.
Annotation Type EnableTransactionManagement. Enables Spring's annotation-driven transaction management capability, similar to the support found in Spring's <tx:*> XML namespace. To be used on @Configuration classes to configure traditional, imperative transaction management or reactive transaction management.
"@Transactional" as itself on any isolation level doesn't enabling any locking. To achieve locking behaviour you should use "@Lock" annotation or use " for update" in your query.
If you're using Spring without Spring Boot, you need to activate the transaction management by annotating your application class with @EnableTransactionManagement. Here you can see a simple example of a service with a transactional method.
It matters where you call the method annotated with @Transactional
. For example if you have:
@Service
public class Service1 {
@Transactional
public void method1() { ... }
public void method2() {
method1();
}
}
@Service
public class Service2 {
@Autowired
private Service1 service1;
public void method1() {
service1.method1();
}
public void method2() {
service1.method2();
}
}
service2.method2()
will NOT create a transaction.service2.method1()
will create one. Because of the way Spring handles Proxies and AOP.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With