我是靠谱客的博主 魔幻野狼,最近开发中收集的这篇文章主要介绍事务的ACID四大特性·隔离级别·及MVCC保证事务隔离性 | 大别山码将,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

事务:
事务最经典也经常被拿出来说例⼦就是转账了。假如⼩明要给⼩红转账1000元,这个转账会涉及到两个关键操作就是:将⼩明的余额减少1000元,将⼩红的余额增加1000元。万⼀在这两个操作之间突然出现错误⽐如银⾏系统崩溃,导致⼩明余额减少⽽⼩红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。

事务的四大特性(ACID):

  1. 原⼦性: 事务的原⼦性确保动作要么全部完成,要么完全不起作⽤;
  2. ⼀致性: 执⾏事务前后,数据保持⼀致,多个事务对同⼀个数据读取的结果是相同的;
  3. 隔离性: 并发访问数据库时,⼀个⽤户的事务不被其他事务所⼲扰,各并发事务之间数据库是独⽴的;
  4. 持久性: ⼀个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发⽣故障也不会对其有任何影响。

事务的四个隔离级别:

  • READ-UNCOMMITTED(读未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

    多个事务并发运行会导致:

    • 脏读:指一个事务读取了另外一个事务未提交的数据。
    • 不可重复读:在一个事务内多次读同⼀数据,多次读取结果不同。
    • 幻读:幻读与不可重复读类似。**是指在一个事务内读取到了别的事务插入的数据,导致前后读取数量总量不一致。**⼀个事务在读取⼏⾏数据的时候另⼀个并发事务插⼊了⼀些数据。这时第⼀个事务再次读取数据就会发现多了⼀些原本不存在的记录,就好像发⽣了幻觉⼀样,所以称为幻读。
  • **READ-COMMITTED(读取已提交):**允许读取并发事务已经提交的数据,可以避免脏读,但是幻读或不可重复读仍有可能发⽣。

  • REPEATABLE-READ(可重复读): 对同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改,可以避免脏读和不可重复读,但幻读仍有可能发⽣。

  • SERIALIZABLE(可串⾏化): 最⾼的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰。可以防⽌脏读、不可重复读以及幻读

    因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED**(读取提交内容);MySQL InnoDB 存储引擎的默认⽀持的隔离级别是 (可重复读)。在 分布式事务 的情况下⼀般会⽤到 (可串⾏化) 隔离级别

保证事务隔离的MVCC:

MVCC是在并发访问数据库时,通过保存数据的历史版本,根据比较版本号来处理数据的是否显示,从而达到读取数据的时候不需要加锁就可以保证事务隔离性的效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xlvTAfn4-1632581398444)(C:UsersLENOVO-LXAppDataRoamingTyporatypora-user-imagesimage-20210925185554469.png)]

事务并发流程图:

trx_id:MySQL在事务开始执行的时候分配的事务编号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LC6O8WWH-1632581398460)(C:UsersLENOVO-LXAppDataRoamingTyporatypora-user-imagesimage-20210925190656943.png)]

在InnoDB下两个不同的隔离级别下读取到的结果是不一样的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4M2l6qOx-1632581398465)(C:UsersLENOVO-LXAppDataRoamingTyporatypora-user-imagesimage-20210925210753728.png)]

MVCC是怎样保证事务隔离性的呢?

1.undo_log 版本链

处理事务时使用回滚日志Undo log。Undo log 主要用于记录数据被修改之前的日志,在表信息修改之前先会把数据拷贝到undo log 里,当事务进行回滚时可以通过undo log 里的日志进行数据还原。

InnoDB下两个隔离级别RC和RR基于undo_log 版本链

版本链中每张表都都两个隐藏列trx_id和db_roll_ptr

  • trx_id:记录最后一次更新数据时的事务编号
  • db_roll_ptr:事务指针,指向上一次版本的数据

无论已经提交还是没有提交的数据都会被记录到版本链中,注意版本链中还存有原始数据,它是没有事务编号和事务指针的,都为null

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QPxXNjJz-1632581398477)(C:UsersLENOVO-LXAppDataRoamingTyporatypora-user-imagesimage-20210925182452927.png)]

undo_log 版本链不会断(中间数据不会被删除),因为undo_log 版本链不是立即删除的,MySQL确保版本链数据不再被引用后才会进行删除操作。

2.read_view

在innodb 中每个SQL语句执行前都会得到一个read_view。副本主要保存了当前数据库系统中正处于活跃(没有提交commit)的事务的ID号,其实简单的说这个副本中保存的是系统中当前不应该被本事务看到的其他事务id列表。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8OkOAmGR-1632581398480)(C:UsersLENOVO-LXAppDataRoamingTyporatypora-user-imagesimage-20210925211313952.png)]

Read view 是一个数据结构,包含四个字段:

  • trx_ids: 当前活跃(未提交)事务编号集合。
  • max_trx_id: 预分配事务编号,当前最大事务编号+1
  • min_trx_id: 创建当前read view 时,最小的活跃事务的编号。
  • creator_trx_id: 创建当前read view时的事务编号;

RC隔离级别下,每一次执行快照读都会生成ReadView
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O4hTwerb-1632581398483)(C:UsersLENOVO-LXAppDataRoamingTyporatypora-user-imagesimage-20210925213000560.png)]

我们根据undo_log 版本链和ReadView,参照版本链访问数据规则读取数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nJT9Tk6R-1632581398489)(C:UsersLENOVO-LXAppDataRoamingTyporatypora-user-imagesimage-20210925214624311.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PesNWb78-1632581398491)(C:UsersLENOVO-LXAppDataRoamingTyporatypora-user-imagesimage-20210925215621034.png)]

RC读已提交隔离级别下:select1=张三 select2=张小三

可见出现了不可重复读现象

而RR可重复读只在第一次执行快照读时生成ReadView,后续快照读复用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ESwooXak-1632581398498)(C:UsersLENOVO-LXAppDataRoamingTyporatypora-user-imagesimage-20210925221808661.png)]

所以RR可重复读隔离级别下:select1=张三 select2=张三

解决了不可重复读的现象

但是RR隔离级别下使用MVCC不能完全解决幻读问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eemX9qUl-1632581398507)(C:UsersLENOVO-LXAppDataRoamingTyporatypora-user-imagesimage-20210925222229644.png)]
总结流程图:

img
在这里插入图片描述

最后

以上就是魔幻野狼为你收集整理的事务的ACID四大特性·隔离级别·及MVCC保证事务隔离性 | 大别山码将的全部内容,希望文章能够帮你解决事务的ACID四大特性·隔离级别·及MVCC保证事务隔离性 | 大别山码将所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部