[Spring Boot 23] MyBatis transaction management

I. Overview

Transaction management is essential for enterprise applications. Even if there is an abnormal situation, it can also ensure data consistency.
Spring Framework provides a consistent abstraction for transaction management, and its characteristics are as follows:

Provide a consistent programming model for different transaction APIs, such as JTA (Java Transaction API), JDBC, Hibernate, JPA (Java Persistence API and JDO (Java Data Objects) support declarative transaction management, especially annotation-based declarative transaction management , Simple and easy to use Provides a more simple programmatic transaction management API than other transaction APIs such as JTA, and the perfect integration of spring data access abstraction.

2. Transaction management method

Spring supports two ways of programmatic transaction management and declarative transaction management.

Programmatic transaction management uses TransactionTemplateor directly uses the underlying PlatformTransactionManager. For programmatic transaction management, spring recommends it TransactionTemplate.

Declarative transaction management is based on AOP. Its essence is to intercept before and after the method, then create or add a transaction before the target method starts, and submit or roll back the transaction according to the execution after the target method is executed. The biggest advantage of declarative transactions is that they do not need to be managed by programming, so there is no need to dope transaction management code in the business logic code, and only need to make relevant transaction rule declarations in the configuration file (or through @Transactionalannotation-based Way), you can apply transaction rules to business logic.

Obviously declarative transaction management is better than programmatic transaction management, which is the non-intrusive development method advocated by spring. Declarative transaction management keeps business code free from pollution. An ordinary POJO object can get full transaction support by adding annotations. Compared with programmatic transactions, the only disadvantage of declarative transactions is that the finest granularity of the latter can only be applied to the method level, and cannot be applied to the code block level like programmatic transactions. But even if there is such a demand, there are many alternative methods, for example, the code block that needs to be transaction management can be independent as a method and so on.

There are also two common ways of declarative transaction management, one is based on the xml configuration file of the tx and aop namespaces, and the other is based on @Transactionalannotations. Obviously, the annotation-based approach is simpler, easier to use, and more refreshing.

Three, spring transaction characteristics

All spring transaction management strategy classes inherit from the org.springframework.transaction.PlatformTransactionManagerinterface

public interface PlatformTransactionManager {
 
  TransactionStatus getTransaction(TransactionDefinition definition)
    throws TransactionException;
 
  void commit(TransactionStatus status) throws TransactionException;
 
  void rollback(TransactionStatus status) throws TransactionException;
}

In addition to specifying different transaction managers, you can also control the isolation level and propagation behavior of the transaction, which are explained in detail below:

Four, isolation level

Isolation level refers to the degree of isolation between several concurrent transactions. The main scenarios related to our development include: dirty reads, repeated reads, and phantom reads.
For dirty read, non-repeatable read and phantom read, see: What is dirty read, non-repeatable read, phantom read

We can see org.springframework.transaction.annotation.Isolationthat five values ​​representing the isolation level are defined in the enumeration class:

public enum Isolation {
    DEFAULT(-1),
    READ_UNCOMMITTED(1),
    READ_COMMITTED(2),
    REPEATABLE_READ(4),
    SERIALIZABLE(8);
}
  • DEFAULT: This is the default value, which means that the default isolation level of the underlying database is used. For most databases, this value is usually: READ_COMMITTED.
  • READ_UNCOMMITTED: This isolation level means that a transaction can read data modified by another transaction but not yet committed. This level cannot prevent dirty reads and non-repeatable reads, so this isolation level is rarely used.
  • READ_COMMITTED: This isolation level means that a transaction can only read data that has been committed by another transaction. This level can prevent dirty reads, which is also the recommended value in most cases.
  • REPEATABLE_READ: This isolation level means that a transaction can execute a query multiple times during the entire process, and the records returned each time are the same. Even if there are new data to satisfy the query between multiple queries, these new records will be ignored. This level can prevent dirty reads and non-repeatable reads.
  • SERIALIZABLE: All transactions are executed one by one, so that there is no interference between transactions, that is, this level can prevent dirty reads, non-repeatable reads, and phantom reads. But this will seriously affect the performance of the program. Normally, this level is not used either.

Specify method: Set by using the isolation property, for example:

@Transactional(isolation = Isolation.DEFAULT)

5. Communication behavior

The so-called transaction propagation behavior means that if a transaction context already exists before starting the current transaction, there are several options to specify the execution behavior of a transactional method.

We can see org.springframework.transaction.annotation.Propagationthat 6 enumeration values ​​representing propagation behavior are defined in the enumeration class:

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);
}
  • REQUIRED: If there is a transaction currently, join the transaction; if there is no transaction currently, create a new transaction.
  • SUPPORTS: If there is currently a transaction, then join the transaction; if there is no current transaction, continue to run in a non-transactional manner.
  • MANDATORY: If there is a transaction currently, join the transaction; if there is no transaction currently, an exception is thrown.
  • REQUIRES_NEW: Create a new transaction, if there is a transaction currently, then suspend the current transaction.
  • NOT_SUPPORTED: Run in a non-transactional mode. If there is a transaction currently, the current transaction is suspended.
  • NEVER: Run in non-transactional mode. If there is a transaction currently, an exception is thrown.
  • NESTED: If there is currently a transaction, create a transaction to run as a nested transaction of the current transaction; if there is no current transaction, the value is equivalent to REQUIRED.

Specify method: Set by using the propagation attribute, for example:

@Transactional(propagation = Propagation.REQUIRED)

Six, transaction timeout

The so-called transaction timeout refers to the maximum time a transaction is allowed to execute. If the time limit is exceeded but the transaction has not been completed, the transaction is automatically rolled back. The int value is used to represent the timeout time in TransactionDefinition, and the unit is seconds.

The default setting is the timeout value of the underlying transaction system. If the underlying database transaction system does not set a timeout value, then it is none and there is no timeout limit.

Seven, transaction read-only attributes

Read-only transactions are used when the client code is read-only but do not modify the data. Read-only transactions are used for optimization in specific scenarios, such as when using Hibernate.
The default is read and write transactions.

Eight, spring transaction rollback rules

The recommended way to instruct the spring transaction manager to roll back a transaction is to throw an exception in the context of the current transaction. The spring transaction manager will catch any unhandled exceptions, and then decide whether to roll back the transaction that throws the exception according to the rules.

In the default configuration, Spring rolls back the transaction only when the thrown exception is a runtime unchecked exception, that is, the thrown exception is a subclass of RuntimeException (Errors will also cause the transaction to roll back), and a checked exception is thrown Will not cause the transaction to roll back.
You can explicitly configure to roll back the transaction when those exceptions are thrown, including checked exceptions. You can also clearly define those transactions that are not rolled back when exceptions are thrown.

You can also programmatically use the setRollbackOnly() method to indicate that a transaction must be rolled back. The only operation you can perform after calling setRollbackOnly() is to roll back.

Nine, @Transactional annotation

usage

@Transactional can act on interfaces, interface methods, classes, and class methods. When used as a class, all public methods of the class will have the transaction attribute of this type. At the same time, we can also use this annotation at the method level to override the class-level definition.

Although the @Transactional annotation can be applied to interfaces, interface methods, classes, and class methods, Spring recommends not to use this annotation on interfaces or interface methods, because it will only take effect when interface-based proxies are used. In addition, the @Transactional annotation should only be applied to public methods, which is determined by the nature of Spring AOP. If you use @Transactional annotation on protected, private or default visibility methods, this will be ignored and no exception will be thrown.

By default, only method calls from outside will be captured by the AOP proxy, that is, methods inside a class calling other methods inside this class will not cause transactional behavior, even if the called method is modified by the @Transactional annotation.

Before using @Transactional annotation, please add the annotation @EnableTransactionManagement to the startup class to start the transaction.

@EnableTransactionManagement  //开启事务
public class AdminApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdminApplication.class, args);
    }

}

Note:
Java dynamic proxy uses reflection mechanism to generate an anonymous class that implements proxy interface, and calls InvokeHandler to process it before calling specific methods.

The cglib dynamic proxy uses the asm open source package to load the class file of the proxy object class and process it by modifying its bytecode to generate subclasses.

1. If the target object implements the interface, the dynamic proxy of the JDK will be used to implement AOP by default.
2. If the target object implements the interface, you can force the use of CGLIB to implement AOP
3. If the target object does not implement the interface, you must use the CGLIB library. Spring will automatically switch between JDK dynamic proxy and CGLIB

Guess you like

Origin blog.csdn.net/guorui_java/article/details/109088823