绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
死磕数据库系列(十三):MySQL 事务与隔离级别
2023-03-16 11:37:44


事务的ACID理论

什么是ACID理论?

ACID理论是指在数据库管理系统(DBMS)中事务所具有的四个特性:

  • 原子性(Atomicity
  • 一致性(Consistency
  • 隔离性(Isolation,又称独立性)
  • 持久性(Durability

即在数据库系统中,为了保证一系列数据操作的正确性,可能需要事务的支持,而为了做到功能这么强大的事务,那么这个事务功能就需要支持ACID四个特性!!

ACID的四个特性

  • 原子性

即支持多个操作的原子性,把多个操作放到一个事务中,保证这些操作要么都成功,要么都不成功;MySQL的事务支持操作的回滚,所以支持原子性

  • 一致性

一致性的确是抽象的概念,也蛮不好理解的,因为这名字总会让我联系到数据一致性的错觉。所以我个人偏向于把它理解成一串对数据进行操作的程序执行下来,不会对数据产生不好的影响,比如凭空产生,或消失; 即在事务执行过程中,无论期间执行了多少个对数据的操作,终的数据都应该是一个正确的结果,不会凭空的出现一些数据或少了一些数据。比如一个事务中,对某条记录的金额做出改变,原金额是200,先减少200,再增加200,该事务的操作不会影响到该记录的金额正确性,即根据因果关系,总金额应该还是200,不会是其他的数值;当然多事务并发的情况下也是一样要保证事务的一致性,不管事务怎么并发,怎么修改数据,用户A向用户B转了200块钱,不会出现用户A扣了款,而用户B没有收到的情况;又或者说数据库的总金额就是500块,无论你怎么并发转账,终的总金额也应该是500块钱

  • 隔离性

隔离性的意思就是多个事务之间互相不干扰,即使是并发事务的情况下,他们只是两个并发执行没有交集,互不影响的东西;当然实现中,也不一定需要这么完整隔离性,即不一定需要这么的互不干扰,有时候还是允许有部分干扰的。所以MySQL可以支持4种事务隔离性

  • 持久性

持久性就是当某个操作操作完毕了,那么结果就是这样了,并且这个操作会持久化到日志记录中。操作的结果也不会突然地凭空消失或回滚。MySQL的事务就支持这样的持久性,一旦事务被提交,那个这个操作就执行完了,不会莫名其妙的恢复到执行前的结果或数据丢失。同时如果数据库崩溃或暂停服务,当恢复正常的时候,只要操作已经持久化到日志中,也可以根据日志恢复原来的模样

ACID中C与CAP定理中C的区别?

ACID理论和CAP理论都有一个C,也都叫一致性Consistent, 所以很多人都会把这两个概念当做是一个概念,把自己弄的迷迷糊糊,团团转。没错,我说的就是自己,shame…

首先我要声明,这两个C肯定是有区别的:

  • ACID的C指的是事务中的一致性,在一串对数据进行修改的操作中,保证数据的正确性。即数据在事务期间的多个操作中,数据不会凭空的消失或增加,数据的每一个增删改操作都是有因果关系的;比如用户A想用户B转了200块钱,不会出现用户A扣了款,而用户B没有收到的情况
  • CAP的C则指的是分布式环境中,多服务之间的复制是异步,需要一定耗时的,不是即时瞬间完成。所以可能会造成某个节点的数据修改,将修改的数据同步到其他服务需要一定的时间,如果此时有并发请求过来,请求负载均衡到多个节点,可能会出现多个节点获取的数据不一致的问题,因为请求有可能会落在还没完成数据同步的节点上;而C就是为了做到在分布式集群环境读到的数据是一致的;当然这里的C也有分类,如强一致性,弱一致性,终一致性

所以: 即ACID的C着重强调单数据库事务操作时,要保证数据的完整和正确性; 而CAP理论中的C指的是对一个数据多个备份的读写一致性。

MySQL事务的隔离级别

事务操作可能会出现的数据问题

  • 脏读
    事务A修改了数据,但未提交,而事务B查询了事务A修改过却没有提交的数据,这就是脏读,因为事务A可能会回滚
  • 不可重复读
    事务A 查询了金额,是200块钱,未提交 。事务B在事务A查询完之后,修改了金额,变成了300, 在事务A前提交了;如果此时事务A再查询一次数据,就会发现钱跟上一次查询不一致,是300,而不是200。这就是不可重复读。强调事务A对要操作的数据被别人修改了,但在不知请的情况下拿去做之前的用途
  • 幻读
    事务A先修改了某个表的所有纪录的状态字段为已处理,未提交;事务B也在此时新增了一条未处理的记录,并提交了;事务A随后查询记录,却发现有一条记录是未处理的,很是诧异,刚刚不是全部修改为已处理嘛,以为出现了幻觉,这就是幻读

数据库中总共就4个操作: 增,删,改,查
脏读说的是事务知道了自己本不应该知道的东西,强调的动作是查询,我看到了自己不该看的东西 ; 不可重复读强调的是一个人查的时候,其他人却可以增删改, 但我却不知道数据被改了,还拿去做了之前的用途;幻读强调的是我修改了数据,等我要查的时候,却发现有我没有修改的记录,为什么,因为有其他人了一条新的

事务操作可能出现的更新丢失问题

更新丢失问题有两类:

  • 类更新丢失
    事务A的事务回滚覆盖了事务B已提交的结果
  • 第二类更新丢失
    事务A的提交覆盖了事务B已提交的结果

说白了,就是两个事务之间的写写冲突,类就是一个事务的后回滚覆盖另一个事务的前面的提交;第二类就是一个事务的后提交覆盖另一个事务的前提交;但是我们也不用过于关系更新丢失的问题;

应该经过我自己的测试,MySQL5.7版本下,所有的隔离级别都没有出现更新丢失问题,即MySQL5.7版本下的隔离级别默认都是可以解决更新丢失问题的,所以更新丢失的情况并不好模拟。了解一下就好,我们这里不详细讨论

事务的隔离级别的标准

以下是SQL-92定义的四种事务隔离级别标准:

  • Read Uncommitted 读未提交

限制弱的事务级别,忽略其他事务放置的锁,该级别下的事务可以在读取其他事务修改后(插/删/更)但未提交的的数据;说白了这个级别的事务就是个弱鸡,只能保证多个操作的原子性,完整不能解决并发问题;无法解决脏读,不可重复读,幻读

  • Read Committed 读提交

SQL Server默认级别,指定事务执行期间(未提交)不能读取其他事务还未提交的数据,禁止脏读;但可以读取到其他事务 (插/删/更)操作后并提交了的 数据;从而造成多次查询的数据不一致,即不可重复读,同时也不法避免幻读,因为当前事务执行期间,其他事务可以插入新记录

  • Repeatable Read 可重复读

MySQL的默认级别,事务执行期间(未提交)不能读取其他事务还未提交的数据,也不能其他事务读取更新操作后并提交的数据,所以可以避免脏读和不可重复读;但是可以读取到其他事务插/删操作并提交的数据,因此因为可以读取到其他事务入并提交的新数据,所以可能会造成幻读

  • Serializable 事务同步,串行

严格的事务管理,等于事务同步执行,不允许并发,所以不存在并发问题,所有问题都解决了,但是存在性能问题,执行数据慢

级别隔离强大:读未提交<读已提交<可重复读<串行

标准与实现

注意!敲黑板

上面所说的四种事务隔离机制,虽然说是SQL-92标准定义的,但标准毕竟只是标准,不是真正的实现,即各大数据库会对应有这么几个事务隔离级别,但是每一种数据库对这几种隔离级别的实现都不尽相同,甚至可能使用更为复杂的方案来提高数据库的并发性能。

就像MySQL InnoDB引擎的默认事务级别是Repeatable Read,按上面的标准来说,这个级别它会出现上面例子提到的幻读现象,就是事务A先更新了表中所有记录的某个字段状态为已处理,未提交,此时事务B插入了一条新记录 ,提交了。事务A此时重新查询所有记录,却发现有一条记录还是未处理。但事实上,MySQL的RR级别是不会发生这种幻读的。因为当我事务A更新了所有记录的某个字段,此时事务A会获得对这个表的表锁,因为事务A还没有提交,所以事务A获得的锁没有释放,此时事务B在该表插入新记录,会因为无法获得该表的锁,则导致插入操作被阻塞。只有事务A提交了事务后,释放了锁,事务B才能进行接下去的操作

同时我们在RR级别的MySQL去测试就会发现,正在执行的事务既不能读取到其他事务未提交的数据,也读取不到其他事务增/删/改并提交后的数据(不完全,因为MySQL存在并发优化,即存在当前读和快照读两种情况,所以有部分场景还是会出现不可重复读问题),所以我们可以说MySQL的RR级别的隔离是已经实现解决了脏读,不可重复读和幻读的;不过MySQL的Read Committed级别倒是的确没有处理不可重复读和幻读的问题,所以如果想重现这些问题,可以在RC级下测试。

小结

×即会出现相应的问题,即能解决该类问题。

以上是标准事务隔离的规范处理,但是实际各大数据库是怎么控制自己的事务隔离机制的,就需要我们自己做有针对性的调研了

MySQL SQL 命令模拟测试

select @@tx_isolation

查询当前会话的事务隔离级别

select @@global.tx_isolation

查看当前数据库的全局事务隔离级别

set session transaction isolation level repeatable read

设置当前会话隔离级别

set global transaction isolation level repeatable read

查看数据库全局隔离级别

set autocommit = `\ `set autocommit = 1

会话级别,取消自动提交,则当执行语句commit或rollback时才算结束,1开启自动提交;数据库默认是自动提交

show variables like '%autocommit%'

查看是否开启自动提交

begin` / `start transaction

开启事务

rollback`/`rollback work

回滚事务

select * from information_schema.INNODB_TRX

查看当前正在执行的事务

相关问题

InnoDB的RR级别下其实有部分场景还是会出现不可重复读问题的

首先我们都知道标准的SQL定义中,RR级别(可重复读)是能解决不可重复读问题的,即可以避免不可重复读问题;那什么是不可重复读?我们来回忆一下

事务A先查询了金额,是200块钱,未提交 。事务B在事务A查询完之后,修改了金额,变成了300,在事务A提交了;如果此时事务A再查询一次数据,就会发现钱跟上一次查询不一致,这就是不可重复读

但事实上MySQL InnoDB引擎下的RR级别的表现是什么呢?我们可以在MySQL InnoDB的RR级别下用两种场景进行测试当前读快照读

表1:在上表的顺序下,事务B的在事务A提交修改后的快照读是旧版本数据,而当前读是实时新版本实时数据400

表2:这两种场景的区别就是表2中事务B在事务A提交事务前执行过一次快照读,如果我们了解快照读的话,我们就会知道同一事务下,后续快照读的结果会受到前面快照读结果的影响

所以我们可以整理出一下观点:

  • 1.RR级别下的当前读,是会出现不可重复读问题的
  • 2.RR级别下,没有提前查询的快照读也是会出现不可重复读问题的(不过这种情况未必属于不可重复读的范畴,因为不可重复读强调的是事务B要提前查询一次,后面再查询一次,发现不一致;而没有提前查询的快照读,只有一次查询,本质上没有前后数据的对比,所以从概念理解上,这种场景不应该划入不可重复读问题中
  • 3.RR级别下,只有提前查询过的快照读才是能避免不可重复读问题的

总结:

  • 只有情况1和情况3才符合不可重复读问题定义的验证场景,情况2还无法构成对不可重复读的验证
  • 所以我们可以简单的理解成RR级别下的当前读会出现不可重复读问题,而快照读不会出现不可重复读问题;即MySQL的RR级别解决了快照读(普通select)的不可重复读问题,其他情况属于特殊情况

RR级别以下的RC和RUC级别的本身就会出现不可重复读现象,而S级的串行则连快照读都没有,所以就不再讨论范凑内

InnoDB的RR级别下是如何避免幻读的?

对此我们可以分为表象和内在,表象就是看起来像是什么东西实现的,内在就是实际上是什么实现的,毕竟学习的过程就是透过表象看本质的过程嘛

表象: 快照读(非阻塞读) | 伪MVCC
内在: next-key锁行锁Gap锁

学习之前,我们先来了解一下,什么是MySQL InnoDB下的当前读快照读?

  • 当前读

像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁

  • 快照读

不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的新版本,而有可能是之前的历史版本

来源:https://blog.csdn.net/SnailMann/
article/details/88299127



分享好友

分享这个小栈给你的朋友们,一起进步吧。

数据库专区
创建时间:2020-06-16 18:15:35
数据库是存放数据的仓库。它的存储空间很大,可以存放百万条、千万条、上亿条数据。但是数据库并不是随意地将数据进行存放,是有一定的规则的,否则查询的效率会很低。当今世界是一个充满着数据的互联网世界,充斥着大量的数据。即这个互联网世界就是数据世界。数据的来源有很多,比如出行记录、消费记录、浏览的网页、发送的消息等等。除了文本类型的数据,图像、音乐、声音都是数据。 [2]
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 小雨滴
    专家
  • gaokeke123
    专家
戳我,来吐槽~