DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Actuator Enhancements: Spring Framework 6.2 and Spring Boot 3.4
  • How Spring Boot Starters Integrate With Your Project
  • A Practical Guide to Creating a Spring Modulith Project
  • Structured Logging in Spring Boot 3.4 for Improved Logs

Trending

  • Breaking Bottlenecks: Applying the Theory of Constraints to Software Development
  • How To Develop a Truly Performant Mobile Application in 2025: A Case for Android
  • Performance Optimization Techniques for Snowflake on AWS
  • Memory Leak Due to Time-Taking finalize() Method
  1. DZone
  2. Coding
  3. Frameworks
  4. Spring Boot Transactions: Understanding Transaction Propagation

Spring Boot Transactions: Understanding Transaction Propagation

Need help understanding transaction propagation?

By 
Rida Shaikh user avatar
Rida Shaikh
·
Aug. 12, 19 · Tutorial
Likes (29)
Comment
Save
Tweet
Share
140.5K Views

Join the DZone community and get the full member experience.

Join For Free

In my previous tutorial, Spring Boot Transaction Management Example, we looked at transactions and implemented declarative transaction management. In this tutorial, we look at propagation and its different types. In the next tutorial, we will be looking at Spring Boot Transaction Rollback and Spring Boot Transaction Isolation.

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 a transaction and how will it behave if the calling component/service already has or does not have a transaction created already.
Spring Boot Microservices Transaction Propagation

This tutorial is explained in the following YouTube video.

Getting Started

We will be making use of the Spring Boot transaction project developed in the previous chapter. It had the Organization Service, which makes a call to the Employee Service and the Health Insurance Service.

Also, in the previous example, we added the transaction annotation only to the Organization Service.
But suppose the user wants to call the Employee Service both ways, i.e.:

  • Call using the Organization Service Transaction Propagation Tutorial
  • Call the Employee Service directly.

Transaction Propagation Example

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

We will be looking at the various propagation scenarios by observing the behavior 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

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

EmployeeService called directly:

Transaction Propagation - REQUIRED - Call

Transaction Propagation — SUPPORTS


Transaction Propagation - SUPPORTS

Here, both the Organization Service has the transaction propagation defined as Required, while the Employee Service for 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


 EmployeeService called directly:Transaction Propagation - SUPPORTS-Call

Transaction Propagation — NOT_SUPPORTED


Transaction Propagation - NOT_SUPPORTED

Here, for the Organization Service, we have defined the transaction propagation as REQUIRED, and the Employee Service has 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

 EmployeeService called directly:

Transaction Propagation - NOT_SUPPORTED Call

Transaction Propagation — REQUIRES_NEW


Transaction Propagation - REQUIRES_NEW

Here, for the Organization Service, we have defined the transaction propagation as REQUIRED, and the Employee Service has 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


 EmployeeService called directly:

Transaction Propagation - REQUIRES_NEW Code

Transaction Propagation — NEVER

Transaction Propagation - NEVER

Here, for the Organization Service, we have defined the transaction propagation as REQUIRED, and the Employee Service has 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


 EmployeeService called directly:

Transaction Propagation - NEVER Code

Transaction Propagation — MANDATORY


Transaction Propagation - MANDATORY

Here, for the Organization Service, we have defined the transaction propagation as REQUIRED, and the Employee Service has 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

 EmployeeService called directly:

Transaction Propagation - MANDATORY Code

So, the summary will be as follows:

Propagation Behavior
REQUIRED Always executes in a transaction. If there is an 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 the current transaction exists, then it is supported. If none exists, then it gets executed without a transaction.
NOT_SUPPORTED Always executes without a transaction. If there is an existing transaction, it gets suspended.
REQUIRES_NEW Always executes in a new transaction. If there is an existing transaction, it gets suspended.
NEVER Always executes without any transaction. It throws an exception if there is an existing transaction
MANDATORY

Always executes in a transaction. If there is an existing transaction, it is used. If there is no existing transaction, it will throw an exception.

Spring Framework Spring Boot

Published at DZone with permission of Rida Shaikh. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Actuator Enhancements: Spring Framework 6.2 and Spring Boot 3.4
  • How Spring Boot Starters Integrate With Your Project
  • A Practical Guide to Creating a Spring Modulith Project
  • Structured Logging in Spring Boot 3.4 for Improved Logs

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!