INTRODUCTION
We are learning Transaction Management in spring framework. How it helps us in data integrity in case of any system failure. Also we are learning types of transaction management and which type of transaction should be preferred.
Why Transaction Management ?
Transaction Management is used to maintain the integrity of data in case of system failure. When we have multiple database transaction using Transaction Management it can be treated as one and used to maintain the concurrency. It support ACID property and read/write conflicts. We will understand Transaction Management with example.
Example :
assume user is ordering T-shirt from Flipkart application and user entered the details it gets stored in user_details table. now user order something and go for payment due to some reason payment has been canceled so T-shirt is not ordered for you. But the problem is it's information is stored in user_details table. on large scale , many transaction happen in a day. It is not a good practice.
To overcome above problem Transaction Management comes into picture. So spring provide Transaction Management. In such scenario user data is not stored until the payment is successful.
How to Achieve ?
We can achieve Transaction Management in two ways,
- Declarative Transaction Management :
It best and convenient way to manage transaction management in spring. With declarative transaction management, you can define the transactional behavior at the method level or class level using the @Transactional annotation. Basically it allows you to manage transaction help of configuration instead of hard coding in your application.
Follow below steps to use declarative transaction management,
1) Enable transaction management :
In your spring configuration , you need to enable transaction. You need to add @EnableTransactionManagement annotation at configuration level.
code snippet :
@Configuration
@EnableTransactionManagement
public class SpringConfiguration {
}
2) @Transactional annotation :
Once you enable transaction management , you need to use @Transactional at class level or method level.
code snippet :
- Class level annotation :
@Service
@Transactional
public class SpringManagementService {
}
- Method level annotation :
@Service
public class SpringManagementService {
@Transactional
public void transactionManagement() {
}
}
3) Isolation and Propagation :
@Transactional annotation allows you two attributes Isolation and Propagation.
- Propagation : Propagation defines how transactions interact when multiple methods are invoked. It handle in case of nested method calls where one method is called by another method which is already running in transactional.
- Isolation : Transaction is not affected by another transaction i.e. Helps for concurrent transaction.
code snippet :
@Service
public class SpringManagementService {
@Transactional (propogation = Propogation.REQUIRED , isolation = Isolation.READ_COMMENTED)
public void transactionManagement() {
}
}
Benefits :
1) It allows you to manage transaction using configuration and annotation.
2) It allows you to separate transaction logic and business logic.
3) It preferred when there are lots of transaction logic.
2. Programmatic Transaction Management :
It allow you to manage transaction with the help for programming in your application. As it provide you to write code but it is hard to manage. We can perform programmatic transaction management in two ways , TransactionTemplate and PlateformTransactionManager. It also useful when we have minimum transaction logic.
Benefits
1) Need to manage transaction using so hard to manage the code base.
2) It preferred when there are minimum transaction logic.
3) Difficult to manage the code base.
Drawback
1) It create boilerplate code.
2) lots of business and transaction logic is present in code base.
CONCLUSION :
In both transaction management types, Declarative transaction management is used most due to no drawback and less code implementation.
So lets see Declarative transaction management with example,
Step 1 : Create a spring boot project using Spring Initializr.
Step 2 : Add required maven dependency.
Step 3 : add database configuration in application.properties file.
server.port = 9090
#database configuration
spring.datasource.url=jdbc:mysql://localhost:3307/user_details
spring.datasource.username= suraj
spring.datasource.password= ****
Step 4 : Create model class.
We are creating two model class , Passenger and Payment.
@Data
@Builder
@NoArgsContructor
@AllArgsConstructor
@Entity
@Table (name = "PASSENGER_INFO")
public class Passenger {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private Long id;
private long mobileNumber;
private String name;
}
@Data
@Builder
@NoArgsContructor
@AllArgsConstructor
@Entity
@Table (name = "PAYMENT_INFO")
public class Payment{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private double amount;
private Passenger passenger;
}
NOTE : To know about annotations used please click here
Step 5 : Create DOA layer.
Create Repository layer , we are creating two classes PassengerRepository and PaymentRepository
which are extending JPARepository<T, Id>.
1) PassengerRepository.class :
import org.springframework.data.jpa.repository.JpaRepository;
public class PassengerRepository extends JPARepository<Passenger , Integer> {
}
2) PaymentRepository.class :
import org.springframework.data.jpa.repository.JpaRepository;
public class PaymentRepository extends JPARepository<Payment, Integer> {
}
Step 6 : Create Implementation Layer i.e. Service Layer :
We are creating two service layer
1) PassengerService.class
@Service
public class PassengerService {
@Autowired
private PassengerRepository passengerRepository;
@Autowired
private PaymentService paymentService;
public Passenger addPassenger (Passenger passenger) throws Exception {
Passenger passengerSaved = this.passengerRepository.save(passenger);
Payment payment = new Payment();
payment.setId(1234);
payment.setAmount(500);
payment.setPassenger(passenger);
this.paymentService.addPayment(payment);
return passengerSaved;
}
}
2) PaymentService.class
@Service
public class PaymentService {
@Autowired
private PaymentRepository paymentRepository;
public Payment addPayment(Payment payment) {
Payment paymentSaved = this.paymentRepository.save(payment);
return paymentSaved;
}
}
Step 7 : Create controller class
@RestController
@RequestMapping("/api/Passenger")
public class Controller {
@Autowired
private PassengerService passengerService;
@PostMapping("/add")
public ResponseEntity<Employee> savePassenger(@RequestBody Passenger passenger) throws Exception{
Passenger passengerSaved = this.passengerService.addPassenger(passenger);
return new ResponseEntity<Employee>(passengerSaved, HttpStatus.CREATED);
}
}
Step 8 : Run the application
You will see the data is stored in both the table successfully.
Step 9 : Interrupt the application
If we get nullPointerException or any type of exception while saving payment details to database, But Passengers details are stored in database. In Transaction management it is not a good practice.
Step 10 : Using Transaction Management :
To overcome above Step 9 issue, Transaction management is used. We will use @Transactional annotation at method level and @EnableTransactionManagement at main class of our spring boot application. We will add @Transactional annotation at addPassenger() method in PassengerService class.
Main class
@SpringBootApplication
@EnableTransactionManagement
public class TransactionManagementApplication {
public static void main(String[] args) {
SpringApplication.run(TransactionManagementApplication.class, args);
}
}
PassengerService.class
@Service
public class PassengerService {
@Autowired
private PassengerRepository passengerRepository;
@Autowired
private PaymentService paymentService;
@Transactional
public Passenger addPassenger (Passenger passenger) throws Exception {
Passenger passengerSaved = this.passengerRepository.save(passenger);
Payment payment = new Payment();
payment.setId(1234);
payment.setAmount(500);
payment.setPassenger(passenger);
this.paymentService.addPayment(payment);
return passengerSaved;
}
}
Step 11 : Run the application again
In step 9 you will get nullPointerException, and passenger_info are stored but payment_info are not stored. After enabling transaction management in you application , passenger_info is not stored nor payment_info. This way the spring has handled the transaction that both passenger and payment data gets stored or no data gets stored.
USEFUL LINKS :
ABOUT US
Suraj Ladda
CONTACT US
surajladda07@gmail.com
0 Comments
Post a Comment