Spring 大白话系列:事务

如何控制事务

本质就是这几句话:
JDBC:
Connection.setAutoCommit(false);
Connection.commit();–提交
Connection.rollback();–回滚

Spring实现事务的步骤:

那我们基于Spring ,在业务里想加一个事务,结合上一篇我们说的AOP 的形式,就可以把上边这代码写在业务逻辑处理之后和处理异常的情况里。这样不就完成事务了么。

前提:

事务和数据库相关,首先得是调用Dao 层。也就是我们原始对象部分:

  1. 原始对象 —》 原始⽅法 —》核⼼功能 (业务处理+DAO调⽤)
  2. DAO作为Service的成员变量,依赖注⼊的⽅式进⾏赋值
public class XXXUserServiceImpl{
 private xxxDAO xxxDAO
 set get

}

步骤一:额外功能部分:

方式 1) 手写MethodInterceptor : (仅推演-实际不用这样写了)

ppublic Object invoke(MethodInvocation invocation){
    try{
        Connection.setAutoCommit(false);
        Object ret = invocation.proceed();
        Connection.commit();
    }catch(Exception e){
        Connection.rollback();
    }
    return ret;
}

既然所有的业务逻辑事务都是可以固定这样写,那是不是可以直接封装在框架里就行了。Spring 的确是这么做的。
方式 2) Sring的封装 (这一部分引入Spring 事务部分就有了。不用单独写)
它封装在了 org.springframework.jdbc.datasource.DataSourceTransactionManager。核心还是上面这几行代码。

步骤二:切入点,通过注解

@Transactional 事务的额外功能加⼊给那些业务⽅法。

  1. 如果加在类上:类中所有的⽅法都会加⼊事务
  2. 如果加在⽅法上:这个⽅法会加⼊事务

步骤三:组装切面

组装切面是连接切入点和额外功能。

Spring 封装了对应的标签,是通过标签这样做的。

<tx:annotation-driven transaction-manager=""/>

那这句话是怎么联系起来的呢?首先有了这个标签,Spring 会通过扫描所有 @Transactional 的注解作为切入点。其次,transaction-manager 这个属性会把步骤一里的额外功能(DataSourceTransactionManager在这个包里)扫描进去。这不就齐活了。


传播属性

描述了事务解决嵌套问题的特征
保证在同一个时间里在嵌套里最多只有一个事务。

required: 有就支持,没有就单开。
support:纯支持,有就支持,没有也不开。
required_new :要有新的。有就挂起外部的,创建新的,没有就直接创建新的。

image.png
特殊注意:
抛出异常时默认情况:
默认 对于RuntimeException及其⼦类 采⽤的是回滚的策略
默认 对于Exception及其⼦类 采⽤的是提交的策略

那如果我们想针对抛出 Exception类,改成用回顾可以么。这就需要设置这两个属性:
rollbackFor = {java.lang.Exception,xxx,xxx} --设置回滚
noRollbackFor = {java.lang.RuntimeException,xxx,xx} --设置不回滚

@Transactional(rollbackFor = {java.lang.Exception.class},noRollbackFor
= {java.lang.RuntimeException.class})
建议:实战中使⽤RuntimeExceptin及其⼦类 使⽤事务异常属性的默认值

事务属性常见配置

  1. 隔离属性 默认值
  2. 传播属性 Required(默认值) 增删改 Supports 查询操作
  3. 只读属性 readOnly false 增删改 true 查询操作
  4. 超时属性 默认值 -1
  5. 异常属性 默认值

即常见配置:
增删改操作 @Transactional
查询操作
@Transactional(propagation=Propagation.SUPPORTS,readOnly=true)

源码解析 -

前置知识参考:Spring源码解析之-- 事务注解 处理流程 分析

1) 为什么加了 Transactional 这个注解,就会有事务

从这个 TransactionInterceptor 入口开始看

1.TransactioanIntercepor.invoke()
TransactionInterceptor 会对我们添加了 @Transactional 注解的方法或者类进行拦截,之后就会在执行业务逻辑之前先调用该类。

@Override
	@Nullable
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be {@code null}.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}

2.TransactionAspectSupport.invokeWithinTransaction

通过类名xxxAspectxxx,我们可以猜到这是一个Aop的代理类。

下面这段逻辑是核心,包含了事务的开启,提交,回滚等

if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
    // Standard transaction demarcation with getTransaction and commit/rollback calls.
    TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

    Object retVal;
    try {
        // This is an around advice: Invoke the next interceptor in the chain.
        // This will normally result in a target object being invoked.
        // 调用目标类,即代理类执行具体业务逻辑
        retVal = invocation.proceedWithInvocation();
    }
    catch (Throwable ex) {
        // target invocation exception
        // 目标调用异常,进行回滚
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
    }
    finally {
        cleanupTransactionInfo(txInfo);
    }
    // 进行提交
    commitTransactionAfterReturning(txInfo);
    return retVal;
}

else {
    ...
}

事务传播属性

那接下来我们来看下事务传播属性是怎么通过配置就生效了呢。在事务执行过程中,我们配置 Propagation= Required 后执行的过程发生了什么?
这部分后续再讲

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值