Discussion of some issues with Spring transactions

Posted by Kibit on Fri, 11 Feb 2022 22:24:52 +0100

When a spring transaction is mentioned, it is reminiscent of four basic characteristics, five isolation levels and seven communication characteristics. I'm sure most people know this, but knowing it's one thing, and using it well is another. When using Spring transactions, I've encountered several serious issues, so I'll make a self-summary here.

Question 1, propagation.NESTED and propagation. REQUIRED_ What is the difference between NEW?

The effect is the same when the caller does not have a transaction. So the premise for discussing this issue here is that the caller has a transaction. PROPAGATION_REQUIRES_NEW starts a new "internal" transaction that is independent of the environment. This transaction will be completely commited or rolled back, independent of external transactions, with its own isolation, its own locks, and so on. When the internal transaction begins to execute, the external transaction is suspended, and when the internal transaction ends, the external transaction continues to execute.
On the other hand, PROPAGATION_NESTED begins a "nested" transaction, which is a true sub-transaction of an existing transaction. When the latent transaction starts executing, it will get a savepoint. If this nested transaction fails, we will roll back to this savepoint. A latent transaction is part of an external transaction and will not be committed until the external transaction has ended.
Thus, PROPAGATION_REQUIRES_NEW and PROPAGATION_ The biggest difference with NESTED is that PROPAGATION_REQUIRES_NEW is a completely new transaction, and PROPAGATION_NESTED is a subtransaction of an external transaction. If the external transaction commit, the nested transaction will also be commit. This rule also applies to roll back.

Q2. Why does @Transactional ly fail?

1. The caller and the callee belong to the same component, and the callee's @Transacational comment is invalid

package com.transacational;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;


@Component
public class Service {

    public void test1(){
        test2();
    }

    @Transactional//Invalid comment here
    public void test2(){

    }
}

2. The callee is not a public method and the callee's @Transacational comment is invalid

@Component
public class Service {

    @Resource
    private Service1 service1;
    
    public void test1(){
        test2();
        service1.test3();
    }

    @Transactional//1. The comment here is invalid
    public void test2(){

    }
}
package com.transacational;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by chenqimiao on 17/10/31.
 */
@Component
public class Service1 {

    @Transactional//2. The comment here is invalid
    protected void test3(){

    }
}

3. Transaction switches are not turned on, such as @EnableTransactionManagement is not used by the startup class in SpringBoot

Q3. How do you understand the @Transactional timeout?

Timeout is a property that allows developers to set timeout times. Default value -1, the time-out is determined by the specific sql system.

/**
 * Created by chenqimiao on 17/10/31.
 */
@Component
public class Service3 {


    @Resource
    private AdminInfoDoMapper adminInfoDoMapper;
    @Transactional(timeout = 4)//Do not time out
    public void test4(){

        adminInfoDoMapper.selectNameById(1);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Specific definition of timeout: from the beginning of a transaction (before the first code execution of this method) to the end of the last Statement execution

So as you write below, the transaction will time out

@Component
public class Service3 {


    @Resource
    private AdminInfoDoMapper adminInfoDoMapper;
    @Transactional(timeout = 4)
    public void test4(){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        adminInfoDoMapper.selectNameById(1);

    }
}

Q4. @Transactional Default rollback policy?

By default, transactions roll back only when exceptions to RuntimeException or its subclasses are caught by a transaction. If you want a transaction to roll back all exceptions, you must specify @Transactional(rollbackFor=Exception.class) manually so that inheriting Exception's subclasses or Exception itself can roll back the transaction.

Topics: Java Spring Interview Transaction