Spring transaction and transaction propagation mechanism

Article directory

  • Why do you need transactions?
  • Review the use of transactions in MySQL
  • Implementation of transactions in Spring
    • programmatic transaction
    • declarative transaction
    • Declarative transaction failure scenarios
  • Isolation level of transactions in Spring
  • Propagation mechanism of Spring transaction

Why do you need transactions?

A transaction is to encapsulate a group of operations into an execution unit. The group of operations either all execute successfully, or all of them fail to execute, and only part of them cannot be executed successfully.

For example, transfer: account A deducts 100, and account B increases by 100. All operations in this group are executed successfully, and one cannot be executed. Otherwise, A will lose 100 for no reason, or B will increase 100 for no reason.

Therefore, transactions are needed to ensure that all operations of this group are executed successfully or all execution fails

Review the use of transactions in MySQL

-- open transaction
begin;

-- perform a set of operations

-- Submit the transaction
commit;

-- rollback transaction
rollback;

Implementation of transactions in Spring

There are two ways to operate transactions in Spring:

  • Declarative transactions (using annotations to automatically open and commit transactions)
  • Programmatic transactions (manually write code to implement transactions)

Programmatic transactions

@RestController
public class UserController {<!-- -->

    //JDBC transaction manager
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    // transaction attributes
    @Autowired
    private TransactionDefinition transactionDefinition;

    @RequestMapping("/delete")
    public int delete(Integer id){<!-- -->
        if(id==null & amp; & amp; id<=0) return 0;
        TransactionStatus transactionStatus = null;
        try{<!-- -->
            // start transaction
            transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
            int n = userService. delete(id);
            //commit transaction
            dataSourceTransactionManager.commit(transactionStatus);
            return n;
        }catch (Exception e){<!-- --> //An exception occurs, and the transaction is rolled back
            //rollback transaction
            dataSourceTransactionManager.rollback(transactionStatus);
        }
        return 0;
    }
}

Declarative transaction

Just add the @Transactional annotation to the method, and start the transaction when the method is in progress. When no exception occurs, submit the transaction after the method is executed. If an exception occurs, the transaction will be rolled back automatically.

Description: If the @Transactional annotation is added to the test method, the method will be rolled back after execution, in order not to pollute the database

@RestController
public class UserController2 {<!-- -->

    @RequestMapping("/delete")
    @Transactional
    public int delete(Integer id){<!-- -->
        if(id==null || id<=0){<!-- -->
            return 0;
        }
        int n = 0;
        n = userService. delete(id);
        return n;
    }
}

Precautions:

  • @Transactional can modify methods and classes. When modifying classes, this annotation only takes effect for public methods in the class. When modifying methods, it only takes effect for public methods
  • @Transactional will not rollback the transaction when the exception is caught

If the exception is caught, we have two solutions:

  1. In the catch code block, the exception is thrown
 @RequestMapping("/delete")
public int delete(Integer id){<!-- -->
if(id==null || id<0){<!-- -->
return 0;
}
try{<!-- -->
int n = 0;
n = userService. delete(id);
return n;
}catch (Exception e){<!-- -->
throw e; //throw the exception again
}
return 0;
}
  1. Manually perform the operation of rolling back the transaction
 @RequestMapping("/delete")
    public int delete(Integer id){<!-- -->
        if(id==null || id<0){<!-- -->
            return 0;
        }
        try{<!-- -->
            int n = 0;
            n = userService. delete(id);
            return n;
        }catch (Exception e){<!-- -->
        //Manually perform transaction rollback operation
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return 0;
    }

Declarative transaction failure scenario

  1. The method modified by @Transactional is a non-public modified method
  2. @Transactional sets the timeout timeout. When the execution time of the method exceeds the timeout time, the transaction will automatically roll back
  3. There is a try-catch code block in the code. When the exception is caught, the rollback operation will not be performed automatically
  4. If the database itself does not support transactions, @Transactional just notifies the database to open, commit, and rollback transactions
  5. In the method (not using @Transactional), other methods using @Transactional are called, and the transaction will also fail

Isolation level of transactions in Spring

There are five isolation levels for transactions in Spring:

  • Isolation.DEFAULT: subject to the isolation level of the connected database
  • Isolation.READ_UNCOMMITTED: read uncommitted
  • Isolation.READ_COMMITTED: Read committed (solves dirty read)
  • Isolation.REPEATABLE_READ: repeatable read (solves dirty read and non-repeatable read)
  • Isolation.SERIALIZABLE: Serialization (solves dirty read, non-repeatable read, phantom read)

Set the isolation level of the transaction in Spring:

@Transactional(isolation = Isolation.SERIALIZABLE) //Add isolation attribute to @Transactional

Propagation mechanism of Spring transaction

The propagation mechanism of Spring transactions describes how multiple methods of starting transactions transfer between these methods when calling each other.

Before figuring out the transaction propagation mechanism, we need to understand two concepts:

  • Run in non-transaction mode: that is, each operation in the method will be automatically submitted after execution, and multiple operations of the method will not be packaged into an atomic operation execution, and its atomicity is not guaranteed
  • Transaction suspension: For example, if method A calls method B, the transaction opened by method A will be suspended, and any database operation operation in method B will not be under the management of the transaction, that is, two transactions are independent of each other and do not interfere with each other

Method B is called in method A, and current in the following description refers to method A

There are seven propagation mechanisms for Spring transactions:

  1. Propagation.REQUIRED: The default transaction propagation mechanism, if the current (A) transaction exists, then (B) joins the (A) transaction, if the current (A) does not exist transaction, then (B) create a new transaction to run
  2. Propagation.SUPPORTS: If there is a transaction currently, join the transaction, if there is no transaction currently, run in a non-transactional mode
  3. Propagation.MANDATORY: If there is a current transaction, join the transaction, if there is no current transaction, throw an exception
  4. Propagation.REQUIRES_NEW: If the current (A) transaction exists, suspend the current transaction, (B) will create a new transaction execution, the two transactions are independent of each other and do not interfere with each other, if the house does not exist Transaction, (B) will also create a new transaction execution
  5. Propagation.NOT_SUPPORTED: (B) run in non-transactional mode, if current (A) transaction exists, suspend (A) transaction
  6. Propagation.NEVER: Run in a non-transactional mode, if there is a current transaction, an exception will be thrown
  7. Propagation.NESTED: If there is a current (A) transaction, then (B) create a transaction to run as a nested transaction of the current (A) transaction, if there is no current transaction, then (B) Create a new thing to run (equivalent to REQUIRED)

Propagation mechanism for setting transactions in Spring:

@Transactional(propagation = Propagation.REQUIRED)

The above propagation mechanisms fall into three categories:

  • Support current transaction: REQUIRED, SUPPORTS, MANDATORY
  • Current transaction not supported: REQUIRES_NEW, NOT_SUPPORTED, NEVER
  • Nested transactions: NESTED

Interview question: What is the difference between joining a transaction, nesting a transaction, and suspending a transaction?

  • Joining a transaction: If an operation in the transaction fails, the entire transaction will be rolled back
  • Transaction suspension: two transactions do not affect each other, operations in a transaction will only affect the transaction in which it is located, and will not affect other transactions
  • Nested transaction: A calls B, and B is executed as a nested transaction. At this time, if an operation in B fails, only the nested transaction will be rolled back at this time, and the external A transaction will not be affected. If An operation in A transaction fails, and A transaction and nested transactions will be rolled back