【黄岛主公众号流量主变现副业项目】Spring事务@Transactional深度讲解

这个项目我们已经已经开过1.0了,整体反响非常不错,稍微小打小闹的学员,每天都可以收入30-50,做的好一点的人,一天收入50-100+。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

这个项目很简单,我们做的就是流量主的广告收益,单片阅读1000左右可以给你带来十几二十的收益,比其他自媒体平台的广告收益要高的太多了。可以说完全是做的被动收益,只需要每天抽出半小时发发文章就行!
hi,各位同学大家好,今天来给大家讲解下spring框架事务的原理。
spring事务有配置文件和注解两种方法,配置文件方式原理这里就不做过多的介绍,本次重点解释注解@Transactional的原理。

一:注解@Transactional的执行原理过程:
在这里插入图片描述
1、服务器启动时进行注解扫描,将所有带有@Transactional的方法都生成一个aop代理对象;
2、调用者在调用方法时,被切入到aop中,实际调用的是aop的代理对象;
3、在aop代理对象中开启了jdbc事务,并调用了真实的方法;
4、aop代理对象得到方法执行的情况作出提交或回滚的操作。

二:为什么抛出异常后事务回滚失败?
某些情况下明明出现异常,并且抛出了,但是回滚却失败了,这是怎么回事呢,要了解这个问题我们就需要深入解读spring的事务源码,其中关键核心的源码在org.springframework.transaction.interceptor.TransactionAspectSupport,其中的方法invokeWithinTransaction控制着事务的逻辑,源码如下:

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;
        }
    }

其中最关键的几行代码我在上面进行了注释,总体的逻辑是先执行一些真实方法的前置切面,再执行真实方法,如果有异常就进行处理(事务回滚),如果没有异常就提交事务,并执行后置增强方法。
所以,要了解事务回滚失败的原因,就需要进一步的探究方法 this.completeTransactionAfterThrowing(txInfo, var16),源码如下:

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;
                }
            }
        }

    }

从源码中可以看出,所处理的都是运行时RuntimeException异常及其之类的异常,也正是这个原因,一些非运行时异常抛出时,spring并未处理,所以没有回滚。
异常集成关系图,如下:
在这里插入图片描述
由上图可以看出像IO,SQL异常如果不进行特定的处理是不会进行事务回滚的。

在源码中,我们还注意到一行细节代码txInfo.getTransactionStatus(),就是执行事务时是根据事务状态来的,这也就有了为什么手动回滚事务的代码是这么写的:

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

点进去源码可以看到,事务状态默认是false(提交的意思),调用此方法后,则改成true(回滚)

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;
    }
    ………………

由此,综上所述,spring事务回滚的原因有两个:
1、抛出的异常是非运行时异常RuntimeException;
2、事务状态被人为的修改。

那么有没有办法解决此问题了?
当然有啦,如果是人为的,只需找到对应代码调整或删除即可;
如果是非运行异常的抛出,spring针对此问题也做了解决方案,有两种方案
1、配置rollbackFor:
@Transactional(rollbackFor = Exception.class)
2、手动回滚事务
在抓取异常后,补仓代码:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 最后抛出异常即可。

rollbackFor是告知spring框架,要抓取非运行时异常,并回滚。=Exception.class是告知spring框架抓取的范围是什么。所以我们也可以自定义异常,只抓取特定的异常进行回滚。

猜你喜欢

转载自blog.csdn.net/ncw8080/article/details/113857831