I have three service classes namely -
1. OrderService with method order()
2. CustomerService with method acceptCustomerInfo()
3. PaymentService with method pay()
Name of implementation classes are OrderServiceImpl, CustomerServiceImpl, PaymentServiceImpl.
From these Implementation classes, DAO layer methods are called
1. OrderDAO - order()
2. CustomerDAO - acceptCustomerInfo()
3. PaymentDAO - pay()
Name of implementation classes on DAO layer are : OrderDAOImpl, CustomerDAOImpl, PaymentDAOImpl
These classes actually interacts with the database either through hibernate or simple jdbc
Now, on front end
i have one button CHECK-OUT, when user clicks on this button all three methods on service layer gets executed in single transaction.
If anyone fails, all should rollback.
how to design/work to ensure this scenario to work correctly???
Easiest would be to set the three service methods to be Transactional each with the Required Propagation, which is the default, so you can just accept the default values for say @Transactional, on all three Service classes and it will work as you expect. If you need it to work differently, then it might be set differently, but how you explain it, just taking the defaults it perfect.
If all 3 service methods are marked as @Transactional and say, the second or third method rolls back, aren't the previous method(s) committed?
Don't you need to have a single wrapper service method (e.g. checkout()) that is marked as @Transactional and calls each of the other 3 service methods so that if one fails to commit, the entire state change made by checkout() is rolled back?
Joined: Sep 13, 2007
Thanks for quick reply to everyone. But friends, the database is updated on DAO layer where user can use either plane JDBC or Hibernate....
Do I not need any changes on DAO layer( for transaction) or it will be handled by spring itself?
Regardless of whether my solution or Mark's works, you should always handle transactions IMO in the service (business) layer, not in DAOs.
My suggestion does have the transaction demarcation on the service layer. And yes, if he had @Transactional on all three service methods, where one calls the other and they are in different service classes, then it will all run in just one transaction. Since the default value for propagation is REQUIRED, which means if there is already a transaction then join it. If there isn't one started, then start a new one. Since the first call would start a new transaction, the next calls to the other service from that first service would run within the very transaction that the first service started.
if I call a.doA() then a, b and c methods will all run in one single transaction. So anything that happens in A, B or C that would cause a rollback, then all three would rollback. That is how propagation REQUIRED works.
Now if his button calls A, then the button calls B, then the button calls C, then that will not work because now the button is in control. It also wouldn't be a clean design to do that from a button. Which is the suggestion of a wrapper service to call A then B then C, in which the method in the wrapper service could be annotated with @Transactional, and he wouldn't need @Transactional on A, B and C, unless he has code elsewhere that call A, B or C and needs transactions, but if he annotates A, B and C with @Transactional, he would also have those and the first wrapper service all handled correctly. But it is specifically all these possible scenarios that it is important to understand propagation settings and what each mean.