Hello,
I would expose a simple post with 2 examples concerning the propagation of a transaction in the application layers (Spring MVC controller, Manager layer, Service Layer, DAO layer) with the use of Propagation.REQUIRED and the readOnly attribute in the @Transactionnal annotation like:
1 | @Transactional (readOnly = true , propagation = Propagation.REQUIRED) |
See the official Spring documentation concerning the propagation.
TEST n°1:
In this 1st test, we will study a simple example with a no-transactional Spring MVC controller MyController:
1 | public class MyController extends MultiActionController { |
2 | public ModelAndView handleMyAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, InterruptedException { |
4 | myManager.myMethod(param1); |
… which calls a manager class MyManagerImpl in the sub-layer:
01 | @Transactional (readOnly = true ) |
03 | public class MyManagerImpl implements MyManager { |
06 | @Transactional (readOnly = false , propagation = Propagation.REQUIRED) |
07 | public void myMethod(String param1){ |
08 | myService.myMethod(param1); |
… which calls a service class MyServiceImpl in the sub-layer:
01 | @Transactional (readOnly = true ) |
03 | public class MyServiceImpl implements MyService { |
06 | @Transactional (readOnly = false , propagation = Propagation.REQUIRED) |
07 | public void myMethod(String param1){ |
09 | myDao.createOrUpdate(myObject); |
… which calls a DAO class MyServiceImpl in the sub-layer:
01 | @Transactional (propagation=Propagation.MANDATORY) |
02 | public class MyDaoHibernateImpl extends GenericDaoImpl<MyObject, String> implements MyDao { |
03 | public void createOrUpdate(T o) { |
05 | if (o instanceof AbstractPersistentObject) { |
06 | if (((AbstractPersistentObject) o).isCreation()) { |
07 | getSession().saveOrUpdate(o); |
09 | getSession().merge(o); |
12 | throw new RuntimeException( "this method support only AbstractPersistentObject" ); |
So, the result is that the data (in database) are modified/updated because:
- the Spring MVC controller MyController is no-transactional component,
- the method MyManagerImpl.myMethod(String param1) is NOT READONLY and supports the current transaction, or will create a new one if none exists (REQUIRED),
- the method MyServiceImpl.myMethod(String param1) is also NOT READONLY and supports the current transaction, or will create a new one if none exists (REQUIRED),
- and the latest MyDaoHibernateImpl supports the current transaction and throws an exception if none exists (MANDATORY).
TEST n°2:
In this 2nd test, we will study a more complex example with a no-transactional Spring MVC controller MyController:
[NO CHANGE]
1 | public class MyController extends MultiActionController { |
2 | public ModelAndView handleMyAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, InterruptedException { |
4 | myManager.myMethod(param1); |
… which calls a manager class MyManagerImpl in the sub-layer. In this example, we will modify the attribute readOnly = false to the value readOnly = true:
[CHANGED]
01 | @Transactional (readOnly = true ) |
03 | public class MyManagerImpl implements MyManager { |
06 | @Transactional (readOnly = true , propagation = Propagation.REQUIRED) |
07 | public void myMethod(String param1){ |
08 | myService.myMethod(param1); |
… which calls a service class MyServiceImpl in the sub-layer:
[NO CHANGE]
01 | @Transactional (readOnly = true ) |
03 | public class MyServiceImpl implements MyService { |
06 | @Transactional (readOnly = false , propagation = Propagation.REQUIRED) |
07 | public void myMethod(String param1){ |
09 | myDao.createOrUpdate(myObject); |
… which calls a DAO class MyServiceImpl in the sub-layer:
[NO CHANGE]
01 | @Transactional (propagation=Propagation.MANDATORY) |
02 | public class MyDaoHibernateImpl extends GenericDaoImpl<MyObject, String> implements MyDao { |
03 | public void createOrUpdate(T o) { |
05 | if (o instanceof AbstractPersistentObject) { |
06 | if (((AbstractPersistentObject) o).isCreation()) { |
07 | getSession().saveOrUpdate(o); |
09 | getSession().merge(o); |
12 | throw new RuntimeException( "this method support only AbstractPersistentObject" ); |
So, we have:
- the Spring MVC controller MyController is no-transactional component,
- the method MyManagerImpl.myMethod(String param1) is READONLY and supports the current transaction, or will create a new one if none exists (REQUIRED),
- the method MyServiceImpl.myMethod(String param1) is also NOT READONLY and supports the current transaction, or will create a new one if none exists (REQUIRED),
- and the latest MyDaoHibernateImpl supports the current transaction and throws an exception if none exists (MANDATORY).
… the result is that the data (in database) are NOT modified/updated because the method MyServiceImpl.myMethod(String param1) supports the current transaction which has been created READNLY in the method MyManagerImpl.myMethod(String param1).
That’s all!!!
Huseyin OZVEREN
Related