mpmp
mpmp

Reputation: 2459

Java: How to handle multiple Hibernate transactions in one request?

I'm not sure where to open my Transaction object. Inside the service layer? Or the controller layer?

My Controller basically has two services, let's call them AService and BService. Then my code goes something like:

public class Controller {
    public AService aService = new AService();
    public BService bService = new BService();

    public void doSomething(SomeData data) {
        //Transaction transaction = HibernateUtil.getSession().openTransaction();
        if (data.getSomeCondition()) {
            aService.save(data.getSomeVar1());
            bService.save(data.getSomeVar2());
        }
        else {
            bService.save(data.getSomeVar2());
        }


        //transaction.commit(); or optional try-catch with rollback 
    }
}

The behavior I want is that if bService#save fails, then I could invoke a transaction#rollback so that whatever was saved in aService would be rolled back as well. This only seems possible if I create one single transaction for both saves.

But looking at it in a different perspective, it looks really ugly that my Controller is dependent on the Transaction. It would be better if I create the Transaction inside the respective services, (something like how Spring @Transactional works), but if I do it that way, then I don't know how to achieve what I want to happen...

EDIT: Fixed code, added another condition. I am not using any Spring dependencies so the usage of @Transactional is out of the question.

Upvotes: 1

Views: 1361

Answers (1)

Naros
Naros

Reputation: 21113

You can accomplish what you're asking with another layer of abstraction and using composition.

public class CompositeABService {
  @Autowired
  private AService aservice;
  @Autowired
  private BService bservice;

  @Transactional
  public void save(Object value1, Object value2) {
    aservice.save( value1 );
    bservice.save( value2 );
  }
}

public class AService {
  @Transactional
  public void save(Object value) {
    // joins an existing transaction if one exists, creates a new one otherwise.
  }
}

public class BService {
  @Transactional
  public void save(Object value) {
    // joins an existing transaction if one exists, creates a new one otherwise.
  }
}

This same pattern is typically used when you need to interact with multiple repositories as a part of a single unit of work (e.g. transaction).

Now all your controller needs to depend upon is CompositeABService or whatever you wish to name it.

Upvotes: 3

Related Questions