(in depth + interview) scenario of abnormal failure of Spring

catalogue

1. The access type of the method is not public

2. Cannot be final

3. Circular call and not managed by Spring

4. Pay attention to multi-threaded scenarios

5. Database engine

6. Exceptions thrown in transaction methods are caught

7. Transaction communication mechanism

8. Nested transactions

 

Referring to the figure of Daiwen senior and someone on Tiktok, (summarized it a long time ago but didn't take notes) the summary written in the Internet cafe (absolutely personal experience), there's no way

1. The access type of the method is not public

When the modifier accessed by the transaction method is non public, the transaction will be invalidated

There are four kinds of access permissions in java: private, default, protected and public. The permissions increase from left to right. If our addUser method changes to other access types, it will fail

@Service
public class EmpService {
 
    @Transactional
    private void addUser(UserModel userModel){
        saveData(userModel);
    }

Let's see how Spring's source code explains if it is not a public target method. Then TransactionAttribute returns null and does not support transactions

2. Cannot be final

Then the problem comes. If I use this method a little more, what about public+final decoration?

When the method is decorated by final, the transaction will also be invalidated

Explanation: as we all know, our Spring transaction bottom layer uses AOP (in essence, dynamic proxy, that is, reflection, which involves a lot of knowledge points), jdk dynamic proxy or cglib (I will say it separately at that time, one is an essential implementation interface, the other is an inherited parent class rewrite Implementation) - > to help us generate proxy classes and realize transaction functions in proxy classes;

Summary: so, you are all final. How can you rewrite or implement this method?, So you can't add transactions

In depth, we need to think about it in combination with JVM class loading + Klass model in it (I haven't changed some problems in it, and it's too lazy). Here, some people who watch a Spring video and talk about it everywhere are diss, keep a low profile, Hahahahahaha

Dynamic agent review_ Fair wants carry's blog -CSDN blog

Java reflection perception_ Fair wants carry's blog -CSDN blog

Class loading some understanding (-)_ Fair wants carry's blog -CSDN blog

jvm - how the bytecode is executed by the jvm + a little thought introduction about threads_ Fair wants carry's blog -CSDN blog_ How the jvm executes bytecode

jvm memory model and local memory_ Fair wants carry's blog -CSDN blog_ jvm memory and local memory 

@Service
public class EmpService {
 
    @Transactional
    public final void addUser(UserModel user){
        save(user);
    }
}

3. Circular call and not managed by Spring

Remember the circular calls between methods. This also happens in the demo written before. If a method is managed by Spring, then if there is another method that calls each other in it, remember that another method that calls each other cannot be managed by Spring, and circular dependency has the same meaning;

In addition, it will fail if it is not managed by Spring

4. Pay attention to multi-threaded scenarios

If another thread in a transaction method add calls an update method in the transaction method add, the add transaction will also fail, because two different threads execute the two methods, then the database connections obtained are different, so there are two different transactions. If an exception is thrown in the update method, the add method will not rollback

@Service
public class EmpService {
 
    @Autowired
    private OrderService orderService;
 
 
    @Transactional
    public void add(User user){
 
        new Thread(()->{
            orderService.update();
        }).start();
    }
 
}
 
@Service
public class OrderService{
 
    @Transactional
    public void update(){
        System.out.println("======================");
    }
 
}

Note: spring transactions are implemented through database connections. A map is saved in the current thread. key is the data source and value is the database connection. The same transaction refers to the same database connection. Only having the same transaction connection can ensure simultaneous commit and rollback. If it is a different thread, the database connection will be different.

5. Database engine

When the database engine does not use innodb, it will also cause transaction failure

SQL advanced_ Fair wants carry's blog -CSDN blog

6. Exceptions thrown in transaction methods are caught

Explanation: to put it simply, if we handle the exception manually in the @transverse transaction method, our Spring will not receive the exception, so how can we rollback - >throw solution, and it is best to throw RuntimeException, otherwise the efficiency is relatively low, why?

In fact, if you have a deep understanding of reflection and class loading, you will know, because our transaction essence is actually based on the dynamic agent idea of reflection implementation, The purpose is to execute our target class methods through the invoke Method in the InvocationHandler interface under the reflection package, and then enhance -- > the essence is to call the member methods in the Method area through the class object of our target class (in Java code, such as: xxx.class.getMethod(), so as to get our Method, and then invoke execution is over)

7. Transaction communication mechanism

If the propagation property of a transaction is set incorrectly, the transaction will also fail. As follows: propagation = propagation The propagation feature of never does not support transactions. If there are transactions, an exception will be thrown.

At present, only these three propagation features can create new things: REQUIRED and REQUIRES_NEW,NESTED

@Service
public class EmpService {
 
 
    @Transactional(propagation = Propagation.NEVER)
    public void add(User user){
        saveData(user);
        updateSataus(user);
    }
 
}

8. Nested transactions

For such code. If the saveData execution succeeds and the updataStatus execution fails, the entire add method will be rolled back. Then the method that saveData executed successfully before will also be rolled back

@Service
public class EmpService {
 
    @Autowired
    private OrderService orderService;
 
 
    @Transactional
    public void add(User user) {
        saveData(user);
        orderService.updateSataus();
    }
 
}
 
@Service
public class OrderService(){
 
    @Transactional(propagation = Propagation.NESTED)
    public void updateSataus(){
        System.out.println("======================");
    }
}

What if our goal is to rollback only the methods that report errors? (however, in general business scenarios, it seems that there are many rollback, which is what I wrote. Similar to the XA mode of seata, it is directly and strongly consistent.)

@Service
public class EmpService {
 
    @Autowired
    private OrderService orderService;
 
 
    @Transactional
    public void add(UserModel userModel) {
        saveData(userModel);
        try {
            orderService.updateSataus();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}
 
@Service
public class OrderService(){
 
    @Transactional(propagation = Propagation.NESTED)
    public void updateSataus(){
        System.out.println("======================");
    }
}

Tags: Java Interview

Posted by libertyct on Sat, 16 Jul 2022 08:55:50 +0930