Spring transactional dont rollback when exception is mapped by ExceptionMapper - spring

I have a RESTFul service (implemented by jersey) . The service is marked with #Transactional.
I declared an ExceptionMapper like this:
#Provider
public class ThrowableMapper implements ExceptionMapper<Throwable> {
private static final Logger log = Logger.getLogger(ThrowableMapper.class);
public Response toResponse(Throwable ex) {
log.error("throwable", ex);
return Response.status(500).entity("Internal Error").type("text/plain").build();
}
}
when exceptionmapper is not declared than transaction is rollback.
However, when i have an ExceptionMapper transaction is commit without rollback.
I assume the reason for for transaction not being rollback is because when exception is caught by ExceptionMapper than spring transaction proxy dosnt detect that exception was thrown ,so transaction is not rollback.
Is there a way to overcome this?

This is not the cleanest solution, but didn't find anything else.
I add this to the ExceptionMapper:
TransactionAspectSupport.currentTransactionStatus( ).setRollbackOnly();

Related

I want nesting of transaction in spring boot using #Transactional annotation

Currently if exception occurs in method C, code is not rolling back database changes from method B. My expectation is method A should manage transaction in such a way that if exception occurs in method C, code should rollback changes done in method B.
I am using spring boot, maven project.
class SomeClassA{
#Autowired
SomeClassB someClassB;
#Autowired
SomeClassC someClassC;
#Transactional
public A(){
try{
//This method works fine with some database operations.
someClassB.B();
//In this method, exception occurrs.
someClassC.C();
}
catch(Exception e){
}
}
}
class SomeClassB{
#Transactional
public B(){
//some code with database operation
}
}
class SomeClassC{
#Transactional
public C(){
//some code with database operation
//some exception occurs here
}
}
Is it a Checked or Runtime exception ?
Because the default behaviour of #Transactional says:
Any RuntimeException triggers rollback, and any checked Exception does
not.

Commit failure JPA transaction when invoked through JMS MessageListener

I have a code which works fine but fails when the load is high. Not able to find the route cause of it.
Following is overview of my use case
I am reading message from JMS queue.
Calling one REST API endpoint with the message received.
Saving back the response received from #2 in my database.
Below is code snippet
//Message Listener class which reads the messages from JMS Queue
public class MyListener implements MessageListener {
#Autowired
MyDao myDao;
#Override
public void onMessage(Message message) {
MyResponse resp = callRest(message);
myDao.saveToDb(resp);
}
}
//DAO class which updates my entity
#Component
public class MyDao {
#Autowired
EntityManager entityManager;
#Transactional
public boolean saveToDb(MyResponse resp) {
Query query = entityManager.createQuery("from MyTable mt where mt.id=:id");
query.setParameter("id", myResp.getId());
MyTable myTab = (MyTable) query.getSingleResult();
myTab.setProcessFlag(true);
entityManager.merge(myTab);
}
}
This works fine when I run in debug mode or when the messages are coming in queue not so frequently.
But when messages coming in queue are very fast then I get exception
in saveToDb method as
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
Am I doing anything wrong here or if there is some confusion between JMS and JPA transactions while multiple threads are accessing it simultaneously ?
Thanks in advance.
This exception occurs when you invoke nested methods/services also marked as #Transactional.
For more details

Spring transaction when calling private method

I have two questions.
If I have a method:
#Transactional
public method1(){
method2()
}
public method2(){
dao.save()
}
If there is an exception in method2(), will there be a rollback?
Another question:
If I have a method:
#Transactional
public method1(){
method2()
}
private void method2(){
dao.save()
}
If there is an exception in method2(), will there be a rollback?
Yes, there will be a rollback.
The private methods will run within the same transaction. You should be aware that you can't have a #Transactional private method. It will not work without raising any error. This behavior is explained in Spring Docs:
Due to the proxy-based nature of Spring’s AOP framework, calls within
the target object are by definition not intercepted. For JDK proxies,
only public interface method calls on the proxy can be intercepted.
Yes to both. Transactional method means there must be no error during the entire runtime of the method.
If there is an error on one of the methods you are calling from within, these errors will be propagated and make the transaction fail and rollback.

Spring: how to rollback declarative transaction

In this example, I don't know how to do rollback the transaction if a condition is verified. This is a Spring MVC application with JPA + Hibernate for persistence
In CartController:
#RequestMapping(value="/buy",method=RequestMethod.POST)
public String buy(){
CartDAO.buy();
return "redirect:/";
}//buy
In CartDAOImpl
#Transactional
public class CartDAOImpl implements CartDAO {
#PersistenceContext
private EntityManager em;
public void buy(){
....
if(x !=y) throw new MyException();
em.persist(Item);
....
}
}
In applicationContext-servlet.xml
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
What's the best solution to this problem? Sorry for my English
From Spring documentation about rolling back declarative transactions:
In its default configuration, the Spring Framework’s transaction infrastructure code only marks a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException. ( Errors will also - by default - result in a rollback). Checked exceptions that are thrown from a transactional method do not result in rollback in the default configuration.
You can configure exactly which Exception types mark a transaction for rollback, including checked exceptions. The following XML snippet demonstrates how you configure rollback for a checked, application-specific Exception type.
Source: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative-rolling-back
You can declare in the #Transactional that you want Spring to performa a rollback when your MyException is thrown:
#Transactional(rollbackFor=MyException.class)

EJB with spring : transaction issue in JPA flush

I have an issue with an injected EntityManager in my MessageDriven Bean that use spring bean as services (the bootstrap is done with the SpringBeanAutowiringInterceptor.
Here is the code :
#MessageDriven(name = "ProcessMDB")
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class ProcessMDB implements MessageListener {
#Autowired
private ProcessService processService;
#Override
public void onMessage(Message message) {
try {
id = message.getLongProperty("ID");
processService.process(id);
} catch (Exception e) {
// Handle error.
}
}
The process service has a DAO where the EntityManager is injected with the annotation #PersistentContext...
The problem is that if a JPA error occurs in the processService, it may occur during the entityManager.flush() call... so the try catch block is gone and the //Handle error stuff is not done.
So I tried to add manually the flush.
#MessageDriven(name = "ProcessMDB")
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class ProcessMDB implements MessageListener {
#Autowired
private ProcessService processService;
#PersistenceContext
private EntityManager em;
#Override
public void onMessage(Message message) {
try {
id = message.getLongProperty("ID");
processService.process(id);
em.flush();
} catch (Exception e) {
// Handle error.
}
}
But it seems that the flush has no effect.
I've try to add the em.flush in the underlying DAO (just after the persist for instance) and it works! The exception is well raised and the catch block is executed. But it doesn't work if I put the em.flush() at the MessageDrivenBean level.
I think that it's transaction manager problem... The entitymanager in spring beans is not in the same tx than the injected entity manager in my ejb.
If I make em.find in the onMessage() method, the fetched object holds old values (the one in the database), not values that are changed in the service method.
I've configured my database as followed :
<jee:jndi-lookup id="emf" jndi-name="persistence/PUnit" />
and my tx manager as followed :
<tx:annotation-driven/>
<tx:jta-transaction-manager />
What do I wrong?
Can someonee help me?
Thanks
Stéphane
You have injected EntityManager in ProcessMDB, but the object is being persisted in ProcessService.
Now, how can any operation in ProcessMDB can affect ProcessService, both will have probably their own individual EntityManager.
Scope of PersistenceContext is upto associated EntityManager. The object will be in the context of ProcessService & not in ProcessMDB, therefore calling flush on later will have no effect & this is expected behaviour.

Resources