0

We are using Spring 4.x and Spring Data JPA with declarative transaction management, I have a Controller, Service and a Repository like below pseudo code.

@Service
@Transactional(readOnly=true)
public class SampleService {

     @Autowired
     private SampleRepository sampleRepository;

     @Transactional
     public MyEntity saveMyEntity(MyEntity entity) {
      //do some business logic
      return sampleRepository.save(entity);
     }
}

public class SampleController {

    @Autowired
    private SampleService sampleService; 

    public String saveSample(@Valid MyEntity entity) {
       //Validation
       //If Valid
       sampleService.saveMyEntity(entity);
       //After saving do some view related rendering logic
       //Assume here view related rendering logic throws Exception
       return "view"  
    }
}

In the above code an error gets thrown after call to sampleService.saveMyEntity(entity); but the transaction doesn't mark for rollback, so end user will get an error page but behind the scene entity got persisted.

Is there any way i can rollback the transaction ?

Sreekanth
  • 539
  • 1
  • 7
  • 24
  • Maybe this one could help you: http://stackoverflow.com/questions/16167278/spring-transaction-doesnt-rollback – Teo Jan 18 '16 at 09:35
  • @Teo thanks but Not exactly the same issue, here my sampleService.saveMyEntity method returns without any exception. Here exception is happening after that service call and inside my controller. – Sreekanth Jan 18 '16 at 09:51
  • 1
    The transaction is committed after saveMyEntity() completes. You cannot rollback after that. You would need to widen the scope of the transaction to include the additional logic. – Alan Hay Jan 18 '16 at 09:58
  • @AlanHay to widen the scope i can have two approaches, one is like Shazin mentioned to add Transactional annotation at controller level or Opening transaction in a Filter. To be honest Transactional at controller level doesn't seems like a good practice and still have to cover the scope of exception thrown from other Filter chain, A possible solution would be to start transaction in a filter and handle the commit and rollback manually. But i have no idea if there is any better alternative for this issue. – Sreekanth Jan 18 '16 at 10:17

1 Answers1

1

You can do the following.

@Transactional(rollbackFor=Exception.class)
public String saveSample(@Valid MyEntity entity) {
   //Validation
   //If Valid
   sampleService.saveMyEntity(entity);
   //After saving do some view related rendering logic
   //Assume here view related rendering logic throws Exception
   return "view"  
}

Since the default Transaction Propagation is Required not Required new. Transaction will actually begin at SampleController.saveSample() and the same one will be used SampleService.saveMyEntity(). When an exception thrown from saveSample() the entire transaction will be rolled back.

shazin
  • 21,379
  • 3
  • 54
  • 71
  • its true if i widen the Transaction scope to controller it will work, but i think its not a good practice to add Transaction at controller level. – Sreekanth Jan 18 '16 at 10:09