Series 42: Spring transaction propagation behavior case demonstration (2) #REQUIRED

1. Demonstrate Spring’s default propagation behavior (REQUIRED)

1.1. Data in the table before running

1.2, StockServiceImplREQUIRED

/**
 * @Author: A leaf of duckweed returns to the sea
 * @Date: 2023/10/30 15:43
 * @Description: Demonstrates the propagation behavior of REQUIRED
 * There is no external transaction: open a new transaction
 * External existing transaction: added to the current transaction
 */
@Service(value = "stockServiceREQUIRED")
public class StockServiceImplREQUIRED extends ServiceImpl<StockMapper, StockDO> implements StockService {

    @Resource
    private StockMapper stockMapper;

    @Resource
    private IntegralService integralServiceREQUIRED;

    /**
     *
     * REQUIRED propagation behavior
     * @param id
     * @param num
     * Scenario 1: There are no exceptions in external affairs & internal affairs
     * Expected results: Both external affairs and internal affairs are submitted normally
     * Actual result: Both external affairs and internal affairs are submitted normally
     * Corresponding method: m1()
     *
     * Scenario 2: There are exceptions in external affairs, but there are no exceptions in internal affairs
     * Expected results: Both external and internal transactions are rolled back
     * Actual result: both external and internal transactions are rolled back
     * Corresponding method: m2()
     *
     * Scenario 3: The external transaction is normal, the internal transaction has an exception, but the external transaction captures the exception and throws it
     * Expected results: Both external and internal transactions are rolled back
     * Actual result: both external and internal transactions are rolled back
     * Corresponding method: m3()
     *
     * Scenario 4: The external transaction is normal, but the internal transaction has an exception (the internal transaction captures the exception, but handles it by itself), but the external transaction captures the exception and handles it by itself or throws the exception.
     * Expected results: Both external affairs and internal affairs are submitted normally
     * Actual result: Both external affairs and internal affairs are submitted normally
     * Corresponding method: m4()
     *
     * Scenario 5: The external method does not have a transaction and there is an exception. The internal method has a transaction and there is an exception, but it is not handled or the exception is thrown.
     * Expected results: The external method is submitted normally and the internal method is rolled back
     * Actual result: The external method is submitted normally and the internal method is rolled back
     * Corresponding method: m5()
     *
     *Other scenes:...
     *
     * Summarize:
     * Grasp one principle, the communication characteristics of REQUIRED are:
     * When the external method has a transaction, the called method will share the same transaction with the external method
     * When the external method does not have a transaction, the called method will open a new transaction
     * Then look at how the exception is handled, whether to throw it out or catch the exception yourself and handle it.
     *
     */
    // @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public void reduceStock(Long id, Integer num) {
        m5(id, num);
    }

    private void m5(Long id, Integer num) {
        System.out.println("============>m5() of StockServiceImplREQUIRED was executed...");
        try {
            // Reduce inventory
            StockDO dbStock = stockMapper.selectById(id);
            StockDO updateStock = new StockDO();
            BeanUtils.copyProperties(dbStock, updateStock);
            updateStock.setNum(dbStock.getNum() - num);
            stockMapper.updateById(updateStock);

            // Increase points
            IntegralDO updateIntegral = new IntegralDO();
            updateIntegral.setPreIntegral(0);
            updateIntegral.setCurrentIntegral(1000);
            updateIntegral.setUserId(1L);
            integralServiceREQUIRED.addIntegral(updateIntegral);

            int i = 10 / 0;

        } catch (Exception e) {
            throw new RuntimeException(e);
            // e.printStackTrace();
        }
    }

    private void m4(Long id, Integer num) {
        System.out.println("============>m4() of StockServiceImplREQUIRED was executed...");
        try {
            // Reduce inventory
            StockDO dbStock = stockMapper.selectById(id);
            StockDO updateStock = new StockDO();
            BeanUtils.copyProperties(dbStock, updateStock);
            updateStock.setNum(dbStock.getNum() - num);
            stockMapper.updateById(updateStock);

            // Increase points
            IntegralDO updateIntegral = new IntegralDO();
            updateIntegral.setPreIntegral(0);
            updateIntegral.setCurrentIntegral(1000);
            updateIntegral.setUserId(1L);
            integralServiceREQUIRED.addIntegral(updateIntegral);

        } catch (Exception e) {
            throw new RuntimeException(e);
            // e.printStackTrace();
        }
    }

    private void m3(Long id, Integer num) {
        System.out.println("============>m3() of StockServiceImplREQUIRED was executed...");
        try {
            // Reduce inventory
            StockDO dbStock = stockMapper.selectById(id);
            StockDO updateStock = new StockDO();
            BeanUtils.copyProperties(dbStock, updateStock);
            updateStock.setNum(dbStock.getNum() - num);
            stockMapper.updateById(updateStock);

            // Increase points
            IntegralDO updateIntegral = new IntegralDO();
            updateIntegral.setPreIntegral(0);
            updateIntegral.setCurrentIntegral(1000);
            updateIntegral.setUserId(1L);
            integralServiceREQUIRED.addIntegral(updateIntegral);

        } catch (BeansException e) {
            throw new RuntimeException(e);
        }
    }

    private void m2(Long id, Integer num) {
        System.out.println("============>m2() of StockServiceImplREQUIRED was executed...");
        try {
            // Reduce inventory
            StockDO dbStock = stockMapper.selectById(id);
            StockDO updateStock = new StockDO();
            BeanUtils.copyProperties(dbStock, updateStock);
            updateStock.setNum(dbStock.getNum() - num);
            stockMapper.updateById(updateStock);

            // Increase points
            IntegralDO updateIntegral = new IntegralDO();
            updateIntegral.setPreIntegral(0);
            updateIntegral.setCurrentIntegral(1000);
            updateIntegral.setUserId(1L);
            integralServiceREQUIRED.addIntegral(updateIntegral);

            // Simulate exception
            int i = 10 /0;

        } catch (BeansException e) {
            throw new RuntimeException(e);
        }
    }

    private void m1(Long id, Integer num) {
        System.out.println("============>m1() of StockServiceImplREQUIRED was executed...");
        try {
            // Reduce inventory
            StockDO dbStock = stockMapper.selectById(id);
            StockDO updateStock = new StockDO();
            BeanUtils.copyProperties(dbStock, updateStock);
            updateStock.setNum(dbStock.getNum() - num);
            stockMapper.updateById(updateStock);

            // Increase points
            IntegralDO updateIntegral = new IntegralDO();
            updateIntegral.setPreIntegral(0);
            updateIntegral.setCurrentIntegral(1000);
            updateIntegral.setUserId(1L);
            integralServiceREQUIRED.addIntegral(updateIntegral);

        } catch (BeansException e) {
            throw new RuntimeException(e);
        }
    }
}

1.3, IntegralServiceImplREQUIRED

/**
 * @Author: A leaf of duckweed returns to the sea
 * @Date: 2023/10/30 15:43
 * @Description: Demonstrates the propagation behavior of REQUIRED
 * There is no external transaction: open a new transaction
 * External existing transaction: added to the current transaction
 */
@Service(value = "integralServiceREQUIRED")
public class IntegralServiceImplREQUIRED extends ServiceImpl<IntegralMapper, IntegralDO> implements IntegralService {

    @Resource
    private IntegralMapper integralMapper;

    /**
     *
     * REQUIRED propagation behavior
     * Scenario 1: There are no exceptions in external affairs & internal affairs
     * Expected results: Both external affairs and internal affairs are submitted normally
     * Actual result: Both external affairs and internal affairs are submitted normally
     * Corresponding method: m1()
     *
     * Scenario 2: There are exceptions in external affairs, but there are no exceptions in internal affairs
     * Expected results: Both external and internal transactions are rolled back
     * Actual result: both external and internal transactions are rolled back
     * Corresponding method: m2()
     *
     * Scenario 3: The external transaction is normal, the internal transaction has an exception, but the external transaction captures the exception and throws it
     * Expected results: Both external and internal transactions are rolled back
     * Actual result: both external and internal transactions are rolled back
     * Corresponding method: m3()
     *
     * Scenario 4: The external transaction is normal, but the internal transaction has an exception (the internal transaction captures the exception, but handles it by itself), but the external transaction captures the exception and handles it by itself or throws the exception.
     * Expected results: Both external affairs and internal affairs are submitted normally
     * Actual result: Both external affairs and internal affairs are submitted normally
     * Corresponding method: m4()
     *
     * Scenario 5: The external method does not have a transaction and there is an exception. The internal method has a transaction and there is an exception, but it is not handled or the exception is thrown.
     * Expected results: The external method is submitted normally and the internal method is rolled back
     * Actual result: The external method is submitted normally and the internal method is rolled back
     * Corresponding method: m5()
     *
     *Other scenes:...
     *
     * Summarize:
     * Grasp one principle, the communication characteristics of REQUIRED are:
     * When the external method has a transaction, the called method will share the same transaction with the external method
     * When the external method does not have a transaction, the called method will open a new transaction
     * Then look at how the exception is handled, whether to throw it out or catch the exception yourself and handle it.
     *
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public void addIntegral(IntegralDO updateIntegral) {
        m5(updateIntegral);
    }

    private void m5(IntegralDO updateIntegral) {
        try {
            System.out.println("============>m5() of IntegralServiceImplREQUIRED was executed...");
            integralMapper.insert(updateIntegral);
            // Simulate exception
            int i = 10 / 0;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void m4(IntegralDO updateIntegral) {
        try {
            System.out.println("============>m4() of IntegralServiceImplREQUIRED was executed...");
            integralMapper.insert(updateIntegral);
            // Simulate exception
            int i = 10 / 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void m3(IntegralDO updateIntegral) {
        System.out.println("============>m3() of IntegralServiceImplREQUIRED was executed...");
        integralMapper.insert(updateIntegral);
        // Simulate exception
        int i = 10 / 0;
    }

    private void m2(IntegralDO updateIntegral) {
        System.out.println("============>m2() of IntegralServiceImplREQUIRED was executed...");
        integralMapper.insert(updateIntegral);
    }

    private void m1(IntegralDO updateIntegral) {
        System.out.println("============>m1() of IntegralServiceImplREQUIRED was executed...");
        integralMapper.insert(updateIntegral);
    }

}

1.4, test results

1.5. Data changes

The inventory quantity in the stock table has not changed, and points have not been added to the integral table. In line with expectations

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 138644 people are learning the system