Reputation: 2459
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
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