[Huangdao main public account traffic main monetization side business project] Spring affairs @Transactional in-depth explanation

We have already started this project for 1.0, and the overall response is very good. Those who are a little troublesome can earn 30-50 every day, and those who do better can earn 50-100+ a day.
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here

Insert picture description here
Insert picture description here

This project is very simple. What we do is the advertising revenue of traffic owners. A single reading of 1,000 or so can bring you more than ten to twenty revenues, which is much higher than the advertising revenue of other self-media platforms. It can be said that it is completely passive income, and it only needs to spend half an hour every day to post articles!
Hi, everyone, everyone, today I will explain to you the principles of spring framework affairs.
There are two methods for spring transaction: configuration file and annotation. The principle of configuration file method will not be introduced too much here. This time I will focus on explaining the principle of annotation @Transactional.

One: Annotation @Transactional's implementation principle process:
Insert picture description here
1. Annotation scanning is performed when the server starts, and all methods with @Transactional are generated into an aop proxy object;
2. When the caller calls the method, it is cut into the aop, the actual The proxy object of aop is called;
3. The jdbc transaction is opened in the aop proxy object, and the real method is called;
4. The aop proxy object commits or rolls back when the method is executed.

2: Why does the transaction rollback fail after an exception is thrown?
In some cases, an exception occurred and it was thrown, but the rollback failed. What is going on? To understand this problem, we need to interpret the spring transaction source code in depth. The key core source code is in org.springframework. .transaction.interceptor.TransactionAspectSupport, the method invokeWithinTransaction controls the logic of the transaction, the source code is as follows:

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
    
    
        final TransactionAttribute txAttr = this.getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
        final PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
        final String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
        Object result;
        if (txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
    
    
            final TransactionAspectSupport.ThrowableHolder throwableHolder = new TransactionAspectSupport.ThrowableHolder();

            try {
    
    
                result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, new TransactionCallback<Object>() {
    
    
                    public Object doInTransaction(TransactionStatus status) {
    
    
                        TransactionAspectSupport.TransactionInfo txInfo = TransactionAspectSupport.this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

                        Object var4;
                        try {
    
    
                            Object var3 = invocation.proceedWithInvocation();
                            return var3;
                        } catch (Throwable var8) {
    
    
                            if (txAttr.rollbackOn(var8)) {
    
    
                                if (var8 instanceof RuntimeException) {
    
    
                                    throw (RuntimeException)var8;
                                }

                                throw new TransactionAspectSupport.ThrowableHolderException(var8);
                            }

                            throwableHolder.throwable = var8;
                            var4 = null;
                        } finally {
    
    
                            TransactionAspectSupport.this.cleanupTransactionInfo(txInfo);
                        }

                        return var4;
                    }
                });
                if (throwableHolder.throwable != null) {
    
    
                    throw throwableHolder.throwable;
                } else {
    
    
                    return result;
                }
            } catch (TransactionAspectSupport.ThrowableHolderException var18) {
    
    
                throw var18.getCause();
            } catch (TransactionSystemException var19) {
    
    
                if (throwableHolder.throwable != null) {
    
    
                    this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                    var19.initApplicationException(throwableHolder.throwable);
                }

                throw var19;
            } catch (Throwable var20) {
    
    
                if (throwableHolder.throwable != null) {
    
    
                    this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                }

                throw var20;
            }
        } else {
    
    
            TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

            try {
    
    
                //1.执行调用链,循环调用执行前置方法,真实方法
                result = invocation.proceedWithInvocation();
            } catch (Throwable var16) {
    
    
                //1.2出现异常后,进行处理,回滚事务
                this.completeTransactionAfterThrowing(txInfo, var16);
                throw var16;
            } finally {
    
    
                this.cleanupTransactionInfo(txInfo);
            }
            //2.方法执行顺利,调用后置方法,提交事务
            this.commitTransactionAfterReturning(txInfo);
            return result;
        }
    }

I commented on the most critical lines of code. The overall logic is to execute some front-end aspects of the real method first, and then execute the real method. If there is an exception, it will be processed (transaction rollback), and if there is no exception, it will be submitted. Transaction, and implement post-enhancement methods.
Therefore, to understand the reason for the failure of transaction rollback, you need to further explore the method this.completeTransactionAfterThrowing(txInfo, var16). The source code is as follows:

protected void completeTransactionAfterThrowing(TransactionAspectSupport.TransactionInfo txInfo, Throwable ex) {
    
    
        if (txInfo != null && txInfo.hasTransaction()) {
    
    
            if (this.logger.isTraceEnabled()) {
    
    
                this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex);
            }

            if (txInfo.transactionAttribute.rollbackOn(ex)) {
    
    
                try {
    
    
                    txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
                } catch (TransactionSystemException var7) {
    
    
                    this.logger.error("Application exception overridden by rollback exception", ex);
                    var7.initApplicationException(ex);
                    throw var7;
                } catch (RuntimeException var8) {
    
    
                    this.logger.error("Application exception overridden by rollback exception", ex);
                    throw var8;
                } catch (Error var9) {
    
    
                    this.logger.error("Application exception overridden by rollback error", ex);
                    throw var9;
                }
            } else {
    
    
                try {
    
    
                    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
                } catch (TransactionSystemException var4) {
    
    
                    this.logger.error("Application exception overridden by commit exception", ex);
                    var4.initApplicationException(ex);
                    throw var4;
                } catch (RuntimeException var5) {
    
    
                    this.logger.error("Application exception overridden by commit exception", ex);
                    throw var5;
                } catch (Error var6) {
    
    
                    this.logger.error("Application exception overridden by commit error", ex);
                    throw var6;
                }
            }
        }

    }

It can be seen from the source code that what is processed is runtime RuntimeException and other exceptions. It is for this reason that Spring did not handle some non-runtime exceptions when they were thrown, so there was no rollback.
The abnormal integration relationship diagram is as follows:
Insert picture description here
From the above figure, it can be seen that like IO, SQL exceptions will not be rolled back if they do not undergo specific processing.

In the source code, we also noticed a line of detailed code txInfo.getTransactionStatus(), which is based on the transaction status when the transaction is executed. This is why the code for manually rolling back the transaction is written like this:

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

Click in the source code and you can see that the transaction status is false by default (meaning committed), after calling this method, it will be changed to true (rollback)

public abstract class AbstractTransactionStatus implements TransactionStatus {
    
    
    private boolean rollbackOnly = false;
    private boolean completed = false;
    private Object savepoint;

    public AbstractTransactionStatus() {
    
    
    }

    public void setRollbackOnly() {
    
    
        this.rollbackOnly = true;
    }
    ………………

Therefore, in summary, there are two reasons for spring transaction rollback:
1. The exception thrown is a non-runtime exception RuntimeException;
2. The transaction status is artificially modified.

So is there a way to solve this problem?
Of course, if it is artificial, you only need to find the corresponding code to adjust or delete;
if it is a non-operational exception, Spring has also made a solution to this problem. There are two options
1. Configure rollbackFor:
@Transactional( rollbackFor = Exception.class)
2. Manually roll back the transaction.
After grabbing the exception, call up the position code: TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); Finally, throw the exception.

rollbackFor tells the spring framework to capture non-runtime exceptions and roll them back. =Exception.class tells the scope of the spring framework to capture. So we can also customize exceptions and only grab specific exceptions for rollback.

Guess you like

Origin blog.csdn.net/ncw8080/article/details/113857831