Spring opens transaction process and transaction related configuration

Spring transaction

Spring quick start

Transaction role : guarantee a series of database operations at the data layer with success and failure

The role of Spring transactions: to ensure that a series of database operations succeed and fail at the data layer or business layer

Spring provides an interface PlatformTransactionManager to handle transactions

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

The most basic transaction management implementation class of PlatformTransactionManager interface DataSourceTransactionManager

public class DataSourceTransactionManager {
    
    
    ……
}

Case Study: Simulating a Transfer Between Bank Accounts

Requirement: Realize the transfer operation between any two accounts

Demand miniaturization: A account subtracts money, B account adds money

analyze:

①: The data layer provides basic operations, the designated account loses money (outMoney), and the designated account adds money (inMoney)

②: The business layer provides the transfer operation (transfer), calling the operation of reducing money and adding money

③: Provide 2 account numbers and the operation amount to perform the transfer operation

④: Build the above operations based on Spring integration of MyBatis environment

Result analysis:

①: When the program is executed normally, the account amount A is subtracted and B is added, there is no problem

②: After the execution of the subtraction of the account amount A is completed, the transfer fails after an abnormality occurs in the program, but the operation of subtracting the account amount A succeeds before the abnormality, and the operation of adding the account amount B fails after the abnormality. This is a very big security risk

Implementation steps :

First create a database with id, name, money three fields, and two pieces of data

create table tb_account(
    id int primary key auto_increment,
    name varchar(10),
    money varchar(10)
)

insert into tb_account (name, money)
values ("chenyq", 1000), ("zhangsan", 1000);

Based on the integration of Mybatis and Junit environment ( you can read the previous article if you don’t know ), create a service layer interface AccountService

public interface AccountService {
    
    
    /**
     * @param out 转出对象
     * @param in 转入对象
     * @param money 转出金额
     */
    void transfer(String out, String in, double money);
}

Create the dao layer interface AccountDao, and define a method for adding and subtracting money

public interface AccountDao {
    
    
    @Update("update tb_account set money = money + #{money} where name = #{name};")
    void inMoney(@Param("name") String name, @Param("money") String money);
    
    @Update("update tb_account set money = money - #{money} where name = #{name};")
    void outMoney(@Param("name") String name, @Param("money") String money);
}

The AccountServiceImpl implementation class of the service layer AccountService interface calls the data layer method

@Service
public class AccountServiceImpl implements AccountService {
    
    
    @Autowired
    private AccountDao accountDao;

    public void transfer(String out, String in, double money) {
    
    
        accountDao.outMoney(out, money); // 账户减钱
        accountDao.inMoney(in, money); // 账户加钱
    }
}

Test in the test class, you can see that the modification is successful in the database

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
    
    
    @Autowired
    private AccountService accountService;

    @Test
    public void testTransfer() {
    
    
        accountService.transfer("chenyq", "zhangsan", 100);
    }
}

insert image description here

Next, in the AccountServiceImpl implementation class, after simulating the chenyq account transfer money out, the program is abnormal

@Service
public class AccountServiceImpl implements AccountService {
    
    
    @Autowired
    private AccountDao accountDao;

    public void transfer(String out, String in, double money) {
    
    
        accountDao.outMoney(out, money); // 账户减钱
        int i = 1 / 0; // 模拟程序出现异常
        accountDao.inMoney(in, money); // 账户加钱
    }
}

Re-execute the test class, we can find that although the program reports an error, the money of the chenyq account in the database has decreased by 100

insert image description here

We need to start the Spring transaction, so that the operations of adding money and reducing money can succeed or fail at the same time. The annotation transaction can be added to the business method to indicate that the current method starts the transaction, or it can be added to the interface to indicate that all methods of the current interface start the transaction. Spring enables The transaction steps are as follows

Step 1: Use the @Transactional annotation to start the task, but we generally do not start the transaction in the method of the implementation class, but in the method of the interface to reduce the degree of coupling

public interface AccountService {
    
    
    /**
     * @param out 转出对象
     * @param in 转入对象
     * @param money 转出金额
     */
    @Transactional // 开启事务
    void transfer(String out, String in, double money);
}

Step 2: In the JdbcConfig independent configuration file, define and set a transaction manager, and hand over the transaction manager to Spring management

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    
    
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    transactionManager.setDataSource(dataSource);
    return transactionManager;
}

Step 3: In the Spring core configuration file, enable Spring's annotation support for opening transactions through the EnableTransactionManagement annotation (in simple terms, tell Spring to use annotations to open transactions )

@Configuration
@ComponentScan("com.chenyq")
@PropertySource("classpath:jdbc.properties")
@Import({
    
    JdbcConfig.class, MybatisConfig.class})
@EnableTransactionManagement
public class SpringConfig {
    
    
}

At this point, the transaction is opened and completed. The method of opening the transaction is the same as success and failure. There will be no situation where one business succeeds and the other fails due to abnormalities.

Transaction related configuration

The transaction has the following related configuration :

Attributes effect example
readOnly Set whether it is a read-only transaction readOnly=true read-only transaction
timeout Set transaction timeout timeout = -1 (never timeout)
rollbackFor Set transaction rollback exception (class) rollbackFor = {NullPointException.class}
rollbackForClassName Set transaction rollback exception (String) same format as string
noRollbackFor Set transaction not to rollback exception (class) noRollbackFor = {NullPointException.class}
noRollbackForClassName Set transaction not to rollback exception (String) same format as string
propagation Set transaction propagation behavior ……

Example usage:

@Transactional(readOnly = true, timeout = -1)
void transfer(String out, String in, double money);

Some exceptions do not participate in transaction rollback, we need rollbackFor to set these exceptions to participate in transaction rollback

@Transactional(rollbackFor = {
    
    NullPointException.class})
void transfer(String out, String in, double money);

If we call another method 2 in a method 1 that has opened a transaction, we need to set the transaction multicast behavior when we want the method 1 transaction to roll back, but the method 2 does not roll back

@Transactional(propagation = Propagation.REQUIRES_NEW)

Transaction propagation behavior has additional properties

propagation properties Affairs administrator business coordinator
REQUIRED (default) Turn on T Join T
none New T2
REQUIRES_NEW Turn on T New T2
none New T2
SUPPORTS Turn on T Join T
none none
NOT_SUPPORTED Turn on T none
none none
MANDATORY Turn on T Join T
none ERROR
NEVER Turn on T ERROR
none none
NESTED Set savePoint, once the transaction is rolled back, the transaction will be rolled back to savePoint, and the client will respond to commit/rollback

Guess you like

Origin blog.csdn.net/m0_71485750/article/details/127974104