Spring source learning series blog columns: links

Before learning the source code of transaction management, you need to be familiar with the basic theory of transaction management, so this chapter will describe the basic theory of transaction management

1. What are transactions?

A transaction is a set of atomic SQL operations, or a single unit of work. In computer terms, a program execution unit that accesses and possibly updates various data items in a database

Note: Spring’s transaction support is based on database transactions, which are currently only supported by InnoDB or NDB cluster engines in MySQL databases. The default MyISAM storage engine prior to MySQL5.0 did not support transactions

2. ACID properties of transactions

ACID is an acronym for transaction feature meaning atomicity, Consistency, Isolation, Durability

  • Atomicity: A transaction is an atomic operation consisting of a series of actions. All operations in the entire transaction are either committed successfully or rolled back on failure;
  • Consistency: The database always changes from one consistent state to another consistent state. Data remains consistent before and after a transaction.
  • Isolation: Because there are multiple transactions dealing with the same data, each transaction should be isolated from other transactions to prevent dirty data reads and unrepeatable data reads, etc.
  • Durability: Once a transaction is committed, their modifications are permanently saved to the database. Even if the system crashes, the modified data is not lost.

3, what is dirty reading, non-repeatable reading, magic reading?

  • Dirty read

Before transaction A changes the data and commits the transaction, another transaction B reads the data before transaction A commits the transaction. This situation is called Dirty Read.

  • Unrepeatable read

A transaction is reading some data, and the first read is not the same as the second read because another transaction changed the data between the two reads

  • Phantom read

Unreal reads are similar to unrepeatable reads, but the difference is that unreal reads focus on deleting or adding data from transactions. This is because the second read differs from the first because data is deleted or added by another transaction between the two reads

4. Spring transaction management core interface

5. Transaction isolation level

Definition: The isolation level of a transaction defines the extent to which a transaction may be affected by other concurrent transactions. The isolation level can resolve dirty reads, unrepeatable reads, and phantom reads to varying degrees.

Isolation level describe Dirty read Unrepeatable read Phantom read
ISOLATION_DEFAULT Use the default isolation level of the back-end database, which is Repeatable Read by default. no no is
ISOLATION_READ_UNCOMMITTED Uncommitted read: Allows reading of data that has not yet been committed, which may cause dirty reads, unrepeatable reads, and phantom reads is is is
ISOLATION_READ_COMMITTED Commit reads, which read data that has been committed by concurrent transactions, can prevent dirty reads, but phantom or unrepeatable reads may still occur no is is
ISOLATION_REPEATABLE_READ Repeatable reads can prevent dirty and unrepeatable reads, but phantom reads can still occur no no is
ISOLATION_SERIALIZABLE Serialization, the highest level, follows the ACID isolation level and ensures that dirty, unrepeatable, and phantom reads are prevented no no no

6. Transaction propagation behavior

Transaction propagation behavior describe
PROPAGATION_REQUIRED Yes, default value. If A has A transaction, B will use it; If A does not have A transaction, B creates A new transaction
PROPAGATION_SUPPORTS Support. If A has A transaction, B will use it; If A has no transaction, B will execute nontransactionally
PROPAGATION_MANDATORY Mandatory. If A has A transaction, B will use it. If A has no transaction, B throws an exception
PROPAGATION_REQUIRES_NEW It has to be new. If A has A transaction, suspend A’s transaction and B creates A new transaction. If A has no transaction, B creates A new transaction.
PROPAGATION_NOT_SUPPORTED Is not supported. If A has A transaction, suspend A’s transaction, and B will execute it as A non-transaction. If A has no transaction, B will execute nontransactionally.
PROPAGATION_NEVER Never. If A has A transaction, B throws an exception; If A has no transaction, B will execute nontransactionally
PROPAGATION_NESTED Nesting. The savepoint mechanism is adopted at the bottom layer of A and B to form nested transactions.

7. Other properties of transaction management

Following the introduction of the two important attributes of transaction management, isolation level and propagation behavior, I will look at the other attributes of a transaction

  • Transaction timeout attribute

Transaction timeout. The value of timeout is the maximum time that a transaction is allowed to execute. If the transaction has not completed after this time limit, the transaction is automatically rolled back. The timeout is expressed as an int in seconds. The default value is -1.

  • Transaction read-only attribute

Property value readOnly, for transactions that only read data queries, the transaction type can be specified as readOnly, that is, read-only transactions. Read-only transactions do not involve data modification, and the database provides some means of optimization, so for business-specific interfaces, read-only attributes can be appropriately added

  • Transaction rollback rules

Property value rollbackFor. By default, transactions are rolled back only when they encounter a run-time exception (a subclass of RuntimeException). Error also causes transactions to be rolled back

The property name instructions
propagation The propagation behavior of the transaction, which defaults to REQUIRED
isolation The isolation level of the transaction is DEFAULT
timeout The timeout period for a transaction. The default value is -1, indicating that the transaction will not time out. If other values are set, the transaction will be rolled back automatically if the transaction has not completed
readOnly Specifies that the transaction is read-only. The default value is false
rollbackFor Specifies the type of exception that can trigger transaction rollback, and you can specify more than one exception type.

8. Spring transaction implementation

Spring transaction code is implemented in two ways: programmatic transactions and declarative transactions. The so-called programmatic transaction, it is to point to by the Spring framework provided by the use of the underlying PlatformTransactionManager TransactionTemplate or directly. Declarative transactions, which rely on Spring AOP, declare transaction rules in configuration files or use the @Transactional annotation directly

The following is a typical example of a money transfer, implemented without a transaction, followed by programmatic and declarative transactions for transaction management

package com.example.springframework.dao.impl;

import com.example.springframework.dao.AccountDao;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

/**
 * <pre>
 *      AccountDaoImpl
 * </pre>
 *
 * <pre>
 * @authorMazq * Modified Record * Modified by: Date: 2021/03/25 15:51 Modified: * </pre> */
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

    @Override
    public void out(String outer, int money) {
        super.getJdbcTemplate().update("update account set money = money - ? where usercode=?",money,outer);
    }

    @Override
    public void in(String inner, int money) {
        super.getJdbcTemplate().update("update account set money = money + ? where usercode = ?",money , inner); }}Copy the code
package com.example.springframework.service.impl;

import com.example.springframework.dao.AccountDao;
import com.example.springframework.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Service;


/**
 * <pre>
 *      AccountServiceImpl
 * </pre>
 *
 * <pre>
 * @authorMazq * Modified Record * Modified by: Date: 2021/03/25 15:55 Modified: * </pre> */
@Service
public class AccountServiceImpl extends JdbcDaoSupport implements AccountService {

    AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(final String outer,final String inner,final int money){
        accountDao.out(outer , money);
        // exception
        // int i = 1 / 0;accountDao.in(inner , money); }}Copy the code

The code example looks pretty normal, but if theaccountDao.out(outer , money);.accountDao.in(inner , money);What happens when an exception occurs between two transactions? The result is shown in the picture: Jack’s account has been successfully transferred with 1000, but Tom has not received the remittance. This situation is definitely not allowed in real life, so it needs to use transaction management

Spring programmatic transactions

Spring programmatic transaction implementation, through the Spring framework provided by the use of the underlying PlatformTransactionManager TransactionTemplate or directly

  • useTransactionTemplateThe way of
private AccountDao accountDao;
private TransactionTemplate transactionTemplate;

public void setAccountDao(AccountDao accountDao) {
    this.accountDao = accountDao;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
    this.transactionTemplate = transactionTemplate;
}

@Override
public void transfer(final String outer,final String inner,final int money){
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            accountDao.out(outer , money);
            // exception
            int i = 1 / 0; accountDao.in(inner , money); }}); }Copy the code
  • usePlatformTransactionManagerThe way of
private AccountDao accountDao;

public void setAccountDao(AccountDao accountDao) {
    this.accountDao = accountDao;
}

@Override
public void transferTrans(String outer, String inner, int money) {
    DataSourceTransactionManager dataSourceTransactionManager =
            new DataSourceTransactionManager();
    // Set the data source
    dataSourceTransactionManager.setDataSource(super.getJdbcTemplate().getDataSource());
    DefaultTransactionDefinition transDef = new DefaultTransactionDefinition();
    // Set propagation behavior properties
    transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
    TransactionStatus status = dataSourceTransactionManager.getTransaction(transDef);
    try {
        accountDao.out(outer , money);
        // exception
        int i = 1 / 0;
        accountDao.in(inner , money);
        //commit
        dataSourceTransactionManager.commit(status);
    } catch (Exception e) {
        // rollbackdataSourceTransactionManager.rollback(status); }}Copy the code

Spring declarative transactions

Spring declarative transactions rely on Spring AOP to make the relevant transaction rule declarations in configuration files or directly using the @Transactional annotation

  • AOP rule declaration

This approach configures AOP in the ApplicationContext.xml file to automatically generate proxies for transaction management


      
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="JDBC: mysql: / / 127.0.0.1:3306 / test"></property>
        <property name="username" value="root"></property>
        <property name="password" value="minstone"></property>
    </bean>

    <bean id="accountDao" class="com.example.springframework.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="accountService" class="com.example.springframework.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
        <property name="dataSource" ref="dataSource"></property>
    </bean>
	<! -- Transaction manager configuration -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <! Isolation Isolation level -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
        </tx:attributes>
    </tx:advice>
	
	<! -- Configure all Service methods to support transactions -->
    <aop:config>
     <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.example.springframework.service.. *. * (..) )"/>
 </aop:config>

  
</beans>
Copy the code
  • Use AOP annotations

Set @transactional, proxy-target-class to true for a Transactional class called ApplicationContext. XML. The underlying cglib proxy is enforced

Note that @Transactional can only be used with public methods, either on classes or methods

<! -- Transaction manager configuration -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

<! Configure the Annotation driver to scan the @Transactional Annotation for class defined transactions -->
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
Copy the code

After the above management, once an exception occurs, the transaction is rolled back on both sides, and the transaction is normally committed without exception

The sample code for this article can be found on Github