JavaBlog.fr / Java.lu DEVELOPMENT,Java,Spring Spring: Transaction propagation / readOnly

Spring: Transaction propagation / readOnly

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:

1public class MyController extends MultiActionController {
2    public ModelAndView handleMyAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, InterruptedException {
3        //...
4        myManager.myMethod(param1);
5        //...
6    }
7 
8}

… which calls a manager class MyManagerImpl in the sub-layer:

01@Transactional(readOnly = true)
02@Service("myManager")
03public class MyManagerImpl implements MyManager {
04 
05    @Override
06    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
07    public void myMethod(String param1){
08        myService.myMethod(param1);
09    }
10...
11}

… which calls a service class MyServiceImpl in the sub-layer:

01@Transactional(readOnly = true)
02@Service("myService")
03public class MyServiceImpl implements MyService {
04 
05    @Override
06    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
07    public void myMethod(String param1){
08        //...
09        myDao.createOrUpdate(myObject);
10        //...
11    }
12}

… which calls a DAO class MyServiceImpl in the sub-layer:

01@Transactional(propagation=Propagation.MANDATORY)
02public class MyDaoHibernateImpl extends GenericDaoImpl<MyObject, String> implements MyDao {
03    public void createOrUpdate(T o) {  
04        //...
05        if (o instanceof AbstractPersistentObject) {
06            if (((AbstractPersistentObject) o).isCreation()) {
07                getSession().saveOrUpdate(o);
08            } else {
09                getSession().merge(o);
10            }
11        } else {
12            throw new RuntimeException("this method support only AbstractPersistentObject");
13        }
14        //...
15    }
16 
17}

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]

1public class MyController extends MultiActionController {
2    public ModelAndView handleMyAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, InterruptedException {
3        //...
4        myManager.myMethod(param1);
5        //...
6    }
7 
8}

… 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)
02@Service("myManager")
03public class MyManagerImpl implements MyManager {
04 
05    @Override
06    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
07    public void myMethod(String param1){
08        myService.myMethod(param1);
09    }
10...
11}

… which calls a service class MyServiceImpl in the sub-layer:
[NO CHANGE]

01@Transactional(readOnly = true)
02@Service("myService")
03public class MyServiceImpl implements MyService {
04 
05    @Override
06    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
07    public void myMethod(String param1){
08        //...
09        myDao.createOrUpdate(myObject);
10        //...
11    }
12}

… which calls a DAO class MyServiceImpl in the sub-layer:
[NO CHANGE]

01@Transactional(propagation=Propagation.MANDATORY)
02public class MyDaoHibernateImpl extends GenericDaoImpl<MyObject, String> implements MyDao {
03    public void createOrUpdate(T o) {  
04        //...
05        if (o instanceof AbstractPersistentObject) {
06            if (((AbstractPersistentObject) o).isCreation()) {
07                getSession().saveOrUpdate(o);
08            } else {
09                getSession().merge(o);
10            }
11        } else {
12            throw new RuntimeException("this method support only AbstractPersistentObject");
13        }
14        //...
15    }
16 
17}

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

Leave a Reply

Your email address will not be published.

Time limit is exhausted. Please reload CAPTCHA.

Related Post