Search Tutorials


Spring Boot Transaction Management - Transaction Rollback Example | JavaInUse



Spring Boot Transaction Management - Transaction Rollback Example

In a previous tutorials we had implemented Spring Boot Transaction Management Example - we saw what are transactions and implemented declarative transaction management. In a previous tutorial - Spring Boot Transactions - Understanding Transaction Propagation we also looked at what is propagation and its different types using Spring Boot. In next tutorial we will be looking at what are Transaction Isolations using Spring Boot. In Spring Boot Transaction Management Example we had seen application transaction is a sequence of application actions that are considered as a single logical unit by the application.
OrganizationService Exit
For an application transaction if any action fails then all other actions gets rolled back. Previous Transaction Management Example we had tested the rollback by throwing an unchecked exception.
However in real time scenarios it is the checked exception that gets thrown. These are business exceptions based on some logic
So how will our transactions behave in case of Checked Exceptions? In case of checked exceptions the previously executed transactions do not get rolled back automatically even if we have used transaction annotation. We need to inform the application how to handle roll back in event of checked exception. This is achieved using the RollbackFor annotation.

Spring Boot Transaction Management - Table of Contents

Spring Boot Transaction Management Example Spring Boot Transactions - Understanding Transaction Propagation Spring Boot Transactions - Understanding Transaction Rollbacks Spring Boot Transactions - Understanding Transaction Isolation

Video

This tutorial is explained in the below Youtube Video.

Lets Begin-

We will be modifying the code we had created previously for Transaction Management.
We will create a custom checked exception called InvalidInsuranceAmountException. According to our business logic if the insurance coverage amount is less than zero then this exception should get thrown. The maven project will be as follows -
Spring Boot Microservices Transaction Rollback Maven
Create the Custom Exception as follows-
package com.javainuse.service.impl;

public class InvalidInsuranceAmountException extends Exception {

	private static final long serialVersionUID = 1L;

	public InvalidInsuranceAmountException(String cause) {
		super(cause);
	}

}	
The HealthInsuranceService interface throws this exception for the registerEmployeeHealthInsurance method.
package com.javainuse.service;

import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.impl.InvalidInsuranceAmountException;

public interface HealthInsuranceService {
void registerEmployeeHealthInsurance(EmployeeHealthInsurance employeeHealthInsurance)
throws InvalidInsuranceAmountException;

	void deleteEmployeeHealthInsuranceById(String empid);
}
In the HealthInsuranceServiceImpl class for the registerEmployeeHealthInsurance we put a check for verifying if the coverage amount is less than zero. If it is then we throw the InvalidInsuranceAmountException.
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.HealthInsuranceDao;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.HealthInsuranceService;

@Service
@Transactional
public class HealthInsuranceServiceImpl implements HealthInsuranceService {

	@Autowired
	HealthInsuranceDao healthInsuranceDao;

	@Override
	public void registerEmployeeHealthInsurance(EmployeeHealthInsurance employeeHealthInsurance)
	throws InvalidInsuranceAmountException {
		
	if (employeeHealthInsurance.getCoverageAmount() < 0) {
		throw new InvalidInsuranceAmountException("Coverage Amount Should not be negative");
		}
	healthInsuranceDao.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}

	@Override
	public void deleteEmployeeHealthInsuranceById(String empid) {
		healthInsuranceDao.deleteEmployeeHealthInsuranceById(empid);
	}

}
The OrganizationService interface for the joinOrganization method we throw the InvalidInsuranceAmountException.
package com.javainuse.service;

import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.impl.InvalidInsuranceAmountException;

public interface OrganizationService {

	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance)
	 throws InvalidInsuranceAmountException;

	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance);
}
In the OrganzationServiceImpl which makes a call to the HealthInsuranceService class, we catch the InvalidInsuranceAmountException log it and throw it again. This is because we want the calling client to know what exception has occurred.
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
	@Transactional
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance)
	throws InvalidInsuranceAmountException {
	employeeService.insertEmployee(employee);
	try {
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
		} catch (InvalidInsuranceAmountException e) {
		throw new InvalidInsuranceAmountException("Exception is thrown");
		}
	}

	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}
Finally in the SpringBootJdbcApplication we throw the InvalidInsuranceAmountException.
package com.javainuse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.OrganizationService;
import com.javainuse.service.impl.InvalidInsuranceAmountException;

@SpringBootApplication
public class SpringBootJdbcApplication {
	
	
	@Autowired
	EmployeeService employeeService;

	public static void main(String[] args) throws InvalidInsuranceAmountException {
		ApplicationContext context = SpringApplication.run(SpringBootJdbcApplication.class, args);
		OrganizationService organizationService = context.getBean(OrganizationService.class);

		
		Employee emp= new Employee();
		emp.setEmpId("emp1");
		emp.setEmpName("emp1");
		
		EmployeeHealthInsurance employeeHealthInsurance= new EmployeeHealthInsurance();
		employeeHealthInsurance.setEmpId("emp1");
		employeeHealthInsurance.setHealthInsuranceSchemeName("premium");
		employeeHealthInsurance.setCoverageAmount(0);
	
		organizationService.joinOrganization(emp, employeeHealthInsurance);
	}
}
If now run the application- We see that the employeeService transaction is not rolled back due to an exception in employeeHealthService.
Spring Boot Microservices Transaction without Rollback
In the Database we see that the insert for employee table has not been rolledback-
Spring Boot Microservices Transaction without Rollback database
But this should not be the case. To achieve roll back for checked exception we will need to specify it using Rollbackfor Annotation.
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
@Transactional(rollbackFor = InvalidInsuranceAmountException.class)
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance)
throws InvalidInsuranceAmountException {
	employeeService.insertEmployee(employee);
	try {
	healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	} catch (InvalidInsuranceAmountException e) {
	throw new InvalidInsuranceAmountException("Exception is thrown");
	}
}

@Override
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
	employeeService.deleteEmployeeById(employee.getEmpId());
	healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}
Now run the application again. We see that the employeeService transaction is rolled back due to an exception in employeeHealthService.
Spring Boot Microservices Transaction with Rollback
In the Database we see that the insert for employee table has been rolledback-
Spring Boot Microservices Transaction with Rollback database

Download Source Code

Download it -
Spring Boot Transaction Management Rollback