Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

Saturday, May 4, 2024

Basics of Spring Transactional

Why Spring Transaction?

  • Provides consistent model across JTA (Java Transaction API), JPA (Java Persistence API), JDBC (Java Database Connectivity) and JDO (Java Data Objects)
  • Declarative Transaction Management
  • Simple API for programmatic transaction management - overcomes complexity of JTA.
  • Makes the implementation easy to stub and test.

Transaction with JDBC

import java.sql.Connection;

//...
public void deleteSomething() {
    Connection connection = DriverManager.getConnection(host, user, password); 

    try (connection) {
        connection.setAutoCommit(false);
        Statement deleteStatement = connection.createStatement(); 
        String deleteQuery = "DELETE FROM SOMETHING WHERE SOMETHING_ID = 1";
        deleteStatement.executeQuery(deleteQuery); 
        connection.commit();
    } catch (SQLException e) {
        connection.rollback();
    }
}

//...
With raw JDBC we need to handle commit, rollback, savepoint all on our own. Spring takes away majority of boilerplate code so that we can focus on core business functionalities. 

Transaction with Spring

Above function can be implemented in following way with Spring (assuming the transaction management configuration is in place),

@Transactional
public void deleteSomething() {
    somethingRepository.deleteBySomethingId(1);
}

Spring Transaction Manager




Spring transaction manager mainly rely on definition and status. In definition the nature and behaviour of transaction is defined while the status helps to keep track of transaction journey statuses.

Different Supported transaction managers includes,
  •  DataSourceTransactionManager
  •  JtaTransactionManager
  •  HibernateTransactionManager
  •  JdbcTransactionManager
  •  etc.
This Transactional annotation handles everything behind the scene for use. This annotation has two important configurations - Isolation and Propagation, which we will understand in detail.

Propagation

Transcation propagation defines the nature of transaction handling when there are multiple transactional annottated methods are invoked within the same spring transcation context. 

You can suppy the propagation in Transactional annotation,

@Transactional(propagation = Propagation.REQUIRES_NEW)

Following are supported propagation ways,

  • REQUIRED  → Create new transcation or use existing.
  • SUPPORTS  → Work with or without transaction.
  • MANDATORY  → Do not create transaction but fail if transaction do not exist.
  • REQUIRES_NEW  → Create a new transaction.
  • NOT_SUPPORTED  → Execute without transaction, suspend if transaction exists.
  • NEVER  → Execute without transaction, fail if transaction exists.
  • NESTED  → One physical transaction with multiple savepoints to manage subtransactions.
















Isolation

Isolation level configuration determines the visibility of data between transactions in case of concurrent operations on same database resource. It helps to ensure consistency and integrity of the data. Transaction isolation level is subject to underlying database you are using. We will refer to them in generic sense to get glimps of it.

You can suppy the isolation in Transactional annotation,

@Transactional(isolation = Isolation.DEFAULT)

The isolation levels tackles different concurrent transcation phenomena listed below,
  • Dirty Read : Transaction read uncommitted data of other transaction.
  • Non-repeatable read : Re-read the same data which is now modified by other transaction.
  • Phantom Read : Re-execute the query which returns result set which changed by other transcation.
  • Serialization Anomaly : Inconsistent state of data - group of transactions are committed sequentially with all possible ordering.

Following are supported isolations levels in Spring,
  • DEFAULT → User default isolation level of underlying database.
  • READ_UNCOMMITTED → Allows to read uncommitted data of other transaction. It can not prevent problems may arrise due to concurrency.
  • READ_COMMITTED →  Allows to read committed data of other transaction. Prevents dirty read.
  • REPEATABLE_READ → Prevents dirty read and non-repeatable read (and even phantom read) by returning unchanged data in repeatable reads within same transaction.
  • SERIALIZABLE → Executes transactions sequentially. Solves all consurrency problems but performance suffers.

This can be a starting point for spring transaction learnings, if you have understood the propagation and isolation level well, it becomes easier to configure and debug accordingly.