Spring Boot Transactions - Understanding Transaction Propagation
Tags: springboot, transaction, propagation, springtransaction
Published: 2020-12-25 14:42:57

In previous tutorial - [Spring Boot Transaction Management Example](https://www.javainuse.com/spring/boot-transaction) we saw what are transactions and implemented declarative transaction management. In this tutorial we will be understanding what is propagation and its different types. In next tutorial we will be looking at [Transaction Rollbacks for checked exceptions using Spring Boot.](https://www.javainuse.com/spring/boot-rollback)

**Video**

This tutorial is explained in the below Youtube Video.

{% youtube zVRO-LELoSw %}

Lets Begin-


##What is Transaction Propagation?##
Any application involves a number of services or components making a call to other services or components. Transaction Propagation indicates if any component or service will or will not participate in transaction and how will it **behave if the calling calling component/service already has or does not have a transaction created already.**

![Spring Boot Microservices Transaction Propagation](https://www.javainuse.com/boot-66-18.JPG)

 We will be making use of the Spring Boot Transaction Project we developed in previous chapter. It had the Organization service which makes a call to the Employee Service and the Health Insurance Service.
Also [previous example we had added transaction annotation only to the Organization service.](https://www.javainuse.com/spring/boot-transaction)
But suppose the user wants to call the Employee Service in both ways i.e.
* Call using Organization service
![Transaction Propagation Tutorial](https://www.javainuse.com/boot-67-7-min.JPG)


 
* Call the the Employee Service directly.
![Transaction Propagation Example]
(https://www.javainuse.com/boot-67-8-min.JPG)


As the Employee Service may also be called directly we will need to use Transaction annotation with Employee Service also. So both the services - Organization Service and the Employee Service will be using Transaction annotation.

 We will be looking at the various propagation scenarios by observing the behaviour of the Organization and Employee service. There are six types of Transaction Propagations-
**REQUIRED**
**SUPPORTS**
**NOT_SUPPORTED**
**REQUIRES_NEW**
**NEVER**
**MANDATORY**
##Transaction Propagation - REQUIRED (Default Transaction Propagation)##


![Transaction Propagation - REQUIRED]
(https://www.javainuse.com/boot-67-1-min.JPG)
Here both the Organization Service and the Employee Service have the transaction propagation defined as Required. This is the default Transaction Propagation.
**Code-**
The Organization Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {

	@Autowired
	EmployeeService employeeService;

	@Autowired
	HealthInsuranceService healthInsuranceService;

	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}

	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}
 ```
   

 




 




 
The Employee Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	EmployeeDao employeeDao;

	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}

	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}
```
}
**Output**
**EmployeeService called using OrganizationService** -
![Transaction Propagation - REQUIRED - Output]
(https://www.javainuse.com/boot-67-1-out-min.JPG)

 

 

**EmployeeService called directly** -
![Transaction Propagation - REQUIRED - Call]
(https://www.javainuse.com/boot-67-2-out-min.JPG)

##Transaction Propagation - SUPPORTS##

**Transaction Propagation - SUPPORTS**
![Transaction Propagation - SUPPORTS]
(https://www.javainuse.com/boot-67-2-min.JPG)

Here both the Organization Service has the transaction propagation defined as Required while Employee Service the transaction propagation is defined as **Supports**.
**Code**-
The Organization Service will be as follows-
 ```
package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {

	@Autowired
	EmployeeService employeeService;

	@Autowired
	HealthInsuranceService healthInsuranceService;

	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}

	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}
 ```
The Employee Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional(propagation=Propagation.SUPPORTS)
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	EmployeeDao employeeDao;

	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}

	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}

}
```
**Output**
**EmployeeService called using OrganizationService** -
![Transaction Propagation - SUPPORTS-Code]
(https://www.javainuse.com/boot-67-3-out-min.JPG)

 
 **EmployeeService called directly** -
 Transaction Propagation - SUPPORTS-Call
![Transaction Propagation - NOT_SUPPORTED]
(https://www.javainuse.com/boot-67-3-out-min.JPG)



##Transaction Propagation - NOT_SUPPORTED##
![Transaction Propagation - NOT_SUPPORTED]
(https://www.javainuse.com/boot-67-3-min.JPG)

Here for the Organization Service we have defined the transaction propagation as REQUIRED and the Employee Service have the transaction propagation defined as NOT_SUPPORTED
**Code-**
The Organization Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {

	@Autowired
	EmployeeService employeeService;

	@Autowired
	HealthInsuranceService healthInsuranceService;

	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}

	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}
``` 

 The Employee Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional(propagation=Propagation.NOT_SUPPORTED)
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	EmployeeDao employeeDao;

	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}

	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}

}
```
**Output**
**EmployeeService called using OrganizationService** -
![Transaction Propagation - NOT_SUPPORTED Code]
(https://www.javainuse.com/boot-67-5-out-min.JPG)



 **EmployeeService called directly** -
![Transaction Propagation - NOT_SUPPORTED Call]
(https://www.javainuse.com/boot-67-6-out-min.JPG)


##Transaction Propagation - REQUIRES_NEW##
![Transaction Propagation - REQUIRES_NEW]
(https://www.javainuse.com/boot-67-4-min.JPG)


Here for the Organization Service we have defined the transaction propagation as REQUIRED and the Employee Service have the transaction propagation defined as REQUIRES_NEW
**Code-**
The Organization Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {

	@Autowired
	EmployeeService employeeService;

	@Autowired
	HealthInsuranceService healthInsuranceService;

	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}

	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}
``` 
The Employee Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional(propagation=Propagation.REQUIRES_NEW)
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	EmployeeDao employeeDao;

	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}

	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}

}
```
**Output**
**EmployeeService called using OrganizationService** -
![Transaction Propagation - REQUIRES_NEW Call]
(https://www.javainuse.com/boot-67-7-out-min.JPG)

 **EmployeeService called directly** -
![Transaction Propagation - REQUIRES_NEW Code]
(https://www.javainuse.com/boot-67-7-out-min.JPG)

##Transaction Propagation - NEVER##

![Transaction Propagation - NEVER]
(https://www.javainuse.com/boot-67-5-min.JPG)
Here for the Organization Service we have defined the transaction propagation as REQUIRED and the Employee Service have the transaction propagation defined as NEVERs
**Code-**
The Organization Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {

	@Autowired
	EmployeeService employeeService;

	@Autowired
	HealthInsuranceService healthInsuranceService;

	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}

	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}
 ```
The Employee Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional(propagation=Propagation.NEVER)
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	EmployeeDao employeeDao;

	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}

	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}

}
```
**Output**
**EmployeeService called using OrganizationService** -
![Transaction Propagation - NEVER Call]
(https://www.javainuse.com/boot-67-9-out-min.JPG)

 **EmployeeService called directly** -
![Transaction Propagation - NEVER Code]
(https://www.javainuse.com/boot-67-10-out-min.JPG)

##Transaction Propagation - MANDATORY##

![Transaction Propagation - MANDATORY]
(https://www.javainuse.com/boot-67-6-min.JPG)
Here for the Organization Service we have defined the transaction propagation as REQUIRED and the Employee Service have the transaction propagation defined as MANDATORY
**Code-**
The Organization Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {

	@Autowired
	EmployeeService employeeService;

	@Autowired
	HealthInsuranceService healthInsuranceService;

	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}

	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}
 ```
The Employee Service will be as follows-
```
 package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional(propagation=Propagation.MANDATORY)
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	EmployeeDao employeeDao;

	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}

	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}

}
```
**Output**
**EmployeeService called using OrganizationService** -
![Transaction Propagation - MANDATORY Call]
(https://www.javainuse.com/boot-67-11-out-min.JPG)

 **EmployeeService called directly** -
![Transaction Propagation - MANDATORY Code]
(https://www.javainuse.com/boot-67-12-out-min.JPG)
So the summary will be as follows-
Propagation	Behaviour
REQUIRED	Always executes in a transaction. If there is any existing transaction it uses it. If none exists then only a new one is created
SUPPORTS	It may or may not run in a transaction. If current transaction exists then it is supported. If none exists then gets executed with out transaction.
NOT_SUPPORTED	Always executes without a transaction. If there is any existing transaction it gets suspended
REQUIRES_NEW	Always executes in a new transaction. If there is any existing transaction it gets suspended
NEVER	Always executes with out any transaction. It throws an exception if there is an existing transaction
MANDATORY	Always executes in a transaction. If there is any existing transaction it is used. If there is no existing transaction it will throw an exception.