Title here
Summary here
REQUIRED
Propagation (Default)REQUIRES_NEW
(Independent Transaction)NESTED
(Independent Rollback)MANDATORY
(Requires Existing Transaction)SUPPORTS
(Optional Transaction)NOT_SUPPORTED
(Forces No Transaction)NEVER
(Throws Exception if Called in Transaction)Spring transactions allow control over how transactions behave across method calls using Propagation settings. These determine whether a method runs within an existing transaction or starts a new one.
Propagation Type | Behavior |
---|---|
REQUIRED (default) | Uses the existing transaction if available; otherwise, creates a new one. |
REQUIRES_NEW | Always creates a new transaction, suspending any existing transaction. |
NESTED | Runs within the existing transaction but allows independent rollback for the nested transaction. |
MANDATORY | Requires an active transaction; fails if none exists. |
SUPPORTS | Runs within a transaction if available, but does not create one if none exists. |
NOT_SUPPORTED | Runs outside of a transaction, suspending any existing transaction. |
NEVER | Ensures no transaction exists; throws an error if called within a transaction. |
We’ll modify our Student Management System to demonstrate these behaviors.
Student
Entitypackage com.example.model;
import jakarta.persistence.*;
@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String email;
public Student() {}
public Student(String name, String email) {
this.name = name;
this.email = email;
}
// Getters and Setters
}
package com.example.repository;
import com.example.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepository extends JpaRepository<Student, Integer> {
}
StudentService
package com.example.service;
import com.example.model.Student;
import com.example.repository.StudentRepository;
import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;
@Service
public class StudentService {
private final StudentRepository studentRepository;
private final RegistrationService registrationService;
public StudentService(StudentRepository studentRepository, RegistrationService registrationService) {
this.studentRepository = studentRepository;
this.registrationService = registrationService;
}
@Transactional
public void registerStudent(String name, String email, boolean fail) {
System.out.println("Registering Student: " + name);
studentRepository.save(new Student(name, email));
// Call another transactional method with different propagation
registrationService.registerCourse(name, fail);
}
}
RegistrationService
package com.example.service;
import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;
@Service
public class RegistrationService {
@Transactional(propagation = jakarta.transaction.Transactional.TxType.REQUIRED)
public void registerCourse(String name, boolean fail) {
System.out.println("Registering Course for: " + name);
if (fail) {
throw new RuntimeException("Course registration failed!");
}
}
}
REQUIRED
Propagation (Default)@Service
public class RegistrationService {
@Transactional(propagation = jakarta.transaction.Transactional.TxType.REQUIRED)
public void registerCourse(String name, boolean fail) {
System.out.println("Registering Course for: " + name);
if (fail) {
throw new RuntimeException("Course registration failed!");
}
}
}
Behavior:
StudentService
.registerCourse()
fails, the entire transaction rolls back (both student and course are not saved).REQUIRES_NEW
(Independent Transaction)@Service
public class RegistrationService {
@Transactional(propagation = jakarta.transaction.Transactional.TxType.REQUIRES_NEW)
public void registerCourse(String name, boolean fail) {
System.out.println("Registering Course for: " + name);
if (fail) {
throw new RuntimeException("Course registration failed!");
}
}
}
Behavior:
registerCourse()
runs in a separate transaction.NESTED
(Independent Rollback)@Service
public class RegistrationService {
@Transactional(propagation = jakarta.transaction.Transactional.TxType.NESTED)
public void registerCourse(String name, boolean fail) {
System.out.println("Registering Course for: " + name);
if (fail) {
throw new RuntimeException("Course registration failed!");
}
}
}
Behavior:
registerCourse()
.registerCourse()
fails, only the nested transaction rolls back, but the main transaction continues.MANDATORY
(Requires Existing Transaction)@Service
public class RegistrationService {
@Transactional(propagation = jakarta.transaction.Transactional.TxType.MANDATORY)
public void registerCourse(String name, boolean fail) {
System.out.println("Registering Course for: " + name);
}
}
Behavior:
registerCourse()
is called without an active transaction, it throws an exception.SUPPORTS
(Optional Transaction)@Service
public class RegistrationService {
@Transactional(propagation = jakarta.transaction.Transactional.TxType.SUPPORTS)
public void registerCourse(String name, boolean fail) {
System.out.println("Registering Course for: " + name);
}
}
Behavior:
NOT_SUPPORTED
(Forces No Transaction)@Service
public class RegistrationService {
@Transactional(propagation = jakarta.transaction.Transactional.TxType.NOT_SUPPORTED)
public void registerCourse(String name, boolean fail) {
System.out.println("Registering Course for: " + name);
}
}
Behavior:
NEVER
(Throws Exception if Called in Transaction)@Service
public class RegistrationService {
@Transactional(propagation = jakarta.transaction.Transactional.TxType.NEVER)
public void registerCourse(String name, boolean fail) {
System.out.println("Registering Course for: " + name);
}
}
Behavior:
Propagation Type | Behavior |
---|---|
REQUIRED | Uses the existing transaction, or creates a new one if none exists. |
REQUIRES_NEW | Always creates a new transaction, suspending the existing one. |
NESTED | Runs inside the existing transaction but allows independent rollback. |
MANDATORY | Throws an error if no existing transaction is found. |
SUPPORTS | Uses the existing transaction if available, but runs without one if none exists. |
NOT_SUPPORTED | Always runs outside of a transaction. |
NEVER | Throws an error if called within a transaction. |
β
Try different propagation types and observe rollback behavior.
β
Explore rollback behavior with checked and unchecked exceptions.
π Would you like to explore rollback behavior with checked exceptions next? π