Spirng-事务-基础知识 + 源码阅读

什么是事务?

概念
事务定义

事务,就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。由于其中的一部分或多步执行失败,导致没有步骤被提交,则事务必须回滚到最初的系统状态。

事务特点

原子性:一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做要么全不做
一致性:数据不会因为事务的执行而遭到破坏
隔离性:一个事务的执行,不受其他事务的干扰,即并发执行的事务之间互不干扰
持久性:一个事务一旦提交,它对数据库的改变就是永久的。

原文链接:https://blog.csdn.net/agonie201218/article/details/136189743

不同事务隔离级别下会有什么问题?

事务并发可能产生那些问题?

1 脏读:一个事务读到了另一个事务未提交的数据
2 不可重复读:一个事务读到了另一个事务已经提交(update)的数据。引发事务中的多次查询结果不一致,数据中的值不一致。
3 虚读 /幻读:一个事务读到了另一个事务已经插入(insert)的数据。导致事务中多次查询的结果不一致,比如一个事务向表中插入了一条数据,这个时候另一个事务读取到了这条数据这就是幻读,实际上不应该读到这条数据。
4 丢失更新,举个例子比如事务T1,T2都读取了表中的某一行数据,事务T1对一个表的数据做了更新更为值A,事务T1提交以后,T2也对这个数据进行了修改改为B并提交,这个时候在事务T1里面查询这个数据得到的值是B,T1对数据的修改A被丢失了。
导致这个问题的根本原因就是并发问题,这两个事务可以同时对这个数据进行修改

事务的隔离级别

1 read uncommitted 读未提交【RU】,一个事务读到另一个事务没有提交的数据
存在:3个问题(脏读、不可重复读、幻读)。
2 read committed 读已提交【RC】,一个事务读到另一个事务已经提交的数据
存在:2个问题(不可重复读、幻读)。
解决:1个问题(脏读)
3 repeatable read:可重复读【RR】,在一个事务中读到的数据始终保持一致,无论另一个事务是否提交
解决:3个问题(脏读、不可重复读、幻读)Mysql默认的隔离级别
4 serializable 串行化,同时只能执行一个事务,相当于事务中的单线程
解决:3个问题(脏读、不可重复读、幻读)

怎么使用Spring 事务?事务怎么传播?

直接看这篇文章,写的很好:https://blog.csdn.net/agonie201218/article/details/136189743

事务什么场景下会失效?

可以看这篇文章:
https://blog.csdn.net/mccand1234/article/details/124571619
这里直对3进行补充说明:
场景1:

/**
* 本类的方法申明事务 而被调用的本类方法也申明了事务 会不会生效?
* 结果为: 结果为生效 事务进行了回滚
* 特别强调: 调用本地方法呐
*/

@Transactional(rollbackFor = RuntimeException.class)
public void testRollBack6() {
   this.testRollBackLocal();
   throw new RuntimeException();
}
@Transactional(rollbackFor = RuntimeException.class)
public void testRollBackLocal() {
   int i = this.spuMapper.deleteById("10000017243800");
   throw new RuntimeException();
}

场景2:

/**
* 本类的方法申明事务 而被调用的本类方法没有申明事务 会不会生效?
* 结果为: 结果为生效 事务进行了回滚
* 特别强调: 调用本地方法呐
*/
@Transactional(rollbackFor = RuntimeException.class)
public void testRollBack6() {
   this.testRollBackLocal();
   throw new RuntimeException();
}

public void testRollBackLocal() {
   int i = this.spuMapper.deleteById("10000017243800");
   throw new RuntimeException();
}

参考文章:
https://blog.csdn.net/agonie201218/article/details/136189743
https://blog.csdn.net/mccand1234/article/details/124571619

Spirng 事务源码探索

首先让我们从ProxyTransactionManagementConfiguration开始,我们可以看到这里面注册了3个Bean对象,我们分别在这三个方法上打一个断点,我们会发现,断点首先停在了下面这个Bean:
在这里插入图片描述
这个Bean干了什么事情呢?
我们关注两个地方,一个是构造函数中的true,看到了吧这里就指定了我们的事务只能在public方法上生效。
在这里插入图片描述
然后我们视线来到下面这两个变量,这两个变量是由值从哪里来的呢?嘿嘿,看到了吧,原来是静态代码块来的,很明显我们的工程中是有

在这里插入图片描述
我们看到这个结果:
在这里插入图片描述
所以说这个Bean执行构造函数的时候为我们创建了JtaTransactionAnnotationParser,这个类里面有下面这个方法:
在这里插入图片描述
这不就看到了我们亲爱的@Transactional 注解了,然后我们继续看parseTransactionAnnotation:
在这里插入图片描述
好家伙里面的内容是真不少啊,但是仔细一看是不是发现好熟悉呀,这不就是咱们在@Transactional 注解里可以配置的属性嘛。那除了根据这个变量给我添加了JtaTransactionAnnotationParser,我们看一下前面,别忘了还给我们添加了一个SpringTransactionAnnotationParser哟,这个里面也是做了注解元素据解析,我们后面再来看看到底用的是哪个呢?

好我们继续走,发现断点到下面来了:
在这里插入图片描述

这里又干了什么事情,我们可以看到,创建了一个拦截器,然后把我们上面的transactionAttributeSource通过set进行了注入。好继续走,断点来到了这个Bean,合理的不得了吧,前面两个Bean都在则会个Bean注册的时候用到了。
在这里插入图片描述
好我们发现if中有个enableTx这玩意儿:
在这里插入图片描述
纳尼让我看看哪里来的?索达寺内,原来是在父类里面进行赋值的:
在这里插入图片描述
从这个注解拿一些属性,但是这个注解又在哪里用到了呢?做了怎样的配置?找啊找,好我们找到了TransactionAutoConfiguration里面有这个一段代码,害原来是SpringBoot帮我们做了呀。
在这里插入图片描述
然后我们并没有配置,所以搜采用了注解中的默认值,这里就可以发现是留了属性我们配置的哈:
在这里插入图片描述
好了到这里第三个Bean,BeanFactoryTransactionAttributeSourceAdvisor创建了,然后我们看看里面定义的这个切面,TransactionAttributeSourcePointcut:
在这里插入图片描述
在进行匹配的时候,我们注册的第一个Bean就派上用场了AnnotationTransactionAttributeSource,这块最终会去调用TransactionAnnotationParser 去解析元数据,那到底用的是那个?
在这里插入图片描述
看看,断点进入到这里来了,所以用的是SpringTransactionAnnotationParser。
在这里插入图片描述
到这里我们可以得出结论,当被 @Transactional注解标注的时候,如何能够拦截,是基于AOP去做的,我们在使用@Transactional标注的方法时已经被代理了,这里涉及到AOP什么时机创建代理对象的问题,这里关注事务的源码分析,不在这里进行说明了。
我们继续向后看,竟然被拦截了,那么实现事务的关键就在于这个拦截器帮我们干了什么。
TransactionInterceptor父类有这也一个方法invokeWithinTransaction这个方法特别的长:
在这里插入图片描述
上面进行了事务的创建,并开启事务。下面我们注意一些下图中的三个红框,分别是堆栈调用和开启事务的代码。
在这里插入图片描述
如果发生了异常则是在这个方法里面进行处理的:
在这里插入图片描述
最后提交事务,是在这里
在这里插入图片描述
这里需要注意一些事务提交时机:

  • 方法正常结束:如果方法正常执行完毕(即没有抛出任何未被捕获的异常),那么事务会在方法返回之后提交。
  • 方法抛出异常:如果方法执行过程中抛出了一个未被捕获的异常,并且这个异常不在事务配置的 @Transactional 注解的 rollbackFor 属性中被排除,那么事务将会回滚,不会提交。
  • 手动控制:如果你使用编程式事务管理,可以通过手动控制事务的提交和回滚。
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值