Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate/Spring - Rollback a transaction within a transaction

Given this example code:

public class MyServiceImpl implements MyService {
    @Transactional
    public void myTransactionalMethod() {
        List<Item> itemList = itemService.findItems();
        for (Item anItem : itemList) {
            try {
                processItem(anItem);
            catch (Exception e) {
                // dont rollback here 
                // rollback just one item
            }     
        }

    }

    @Transactional
    public void processItem(Item anItem) { 
        anItem.setSomething(new Something);
        anItem.applyBehaviour();
        itemService.save(anItem);
    }
}

Here is what I want to achieve:

  1. Only processItem(anItem); should rollback if exception occurs inside it.
  2. If exception occurs, myTransactionalMethod should continue, that means the for-each should end.
  3. If exception occurs inside myTransactionalMethod but not in processItem(anItem), myTransactionalMethod should rollback completely.

Is there a solution that doesn't involve managing transactions manually (without annotations)?.

Edit: I was thinking of using @Transactional(PROPAGATION=REQUIRES_NEW), don't know if it will work within the same bean though.

like image 618
dantebarba Avatar asked Sep 11 '25 16:09

dantebarba


1 Answers

This is a common misunderstanding. Spring Transactions are implemented through proxies. Proxies are a wrapper around your class. You are accessing the processItem method from the same class, i.e. you don't go through the proxy, so you don't get any transactions. I explained the mechanism in this answer some years ago.

Solution: you need two separate Spring beans if you want nested transactions, both of them must be proxied by @Transactional.

like image 149
Sean Patrick Floyd Avatar answered Sep 13 '25 04:09

Sean Patrick Floyd