【MySQL】事务隔离级别及ACID

注:begin或start transaction并不是一个事务的起点,而是在执行它们之后的第一个操作InnoDB表的语句,事务才真正开始。start transaction with consistent snapshot命令可以马上启动一个事务。

1、隔离级别

1.1、基本概念

读未提交

当前事务能读取到其他事务尚未提交的修改值。

读提交

当前事务能读取到其他事务已经提交的修改值。

可重复读

一个事务在任何时刻查询到的结果跟事务一开始启动时查询的结果一样。

串行化

强行使所有事务串行执行。

1.2、小测试一

理解了隔离级别的基本概念后,我们做个小测试,看看是不是真的理解了,下面两个会话按顺序执行,最后在各个隔离级别下的V1、V2值各为多少呢?

sessionA sessionB
启动事务
查询得到值1
启动事务
把值1更新成值2
查询得到值V1
提交事务
查询得到值V2
提交事务
查询得到值V3

读未提交可以读取到其他事务未提交的值,所以V1读取到了sessionB未提交的更改,值为2。
读提交不能读取到其他事务未提交的值,所以V1的值为1,当查询V2时,sessionB已经提交了,这时读取到的V2为2。
可重复读查询得到的值为事务启动时的值,所以V1和V2值都为1。
串行化时,sessionA启动事务后,sessionB会被卡住,直至sessionA的事务提交后才执行,所以V1和V2都是1,V3查询时sessionB已经提交事务,所以V3的值为2。

V1 V2 V3
读未提交 2 2 2
读提交 1 2 2
可重复读 1 1 2
串行化 1 1 2

1.3、小测试二

上面的小测试一加深了我们对事务隔离级别的了解,下面我们针对可重复读隔离级别下对小测试一进行修改再加深理解。例子如下:

sessionA sessionB
启动事务
查询得V值为1
启动事务
set V=V+1
查询得到值V1
提交事务
set V=V+1
查询得到值V2
提交事务
查询得到值V3

小测试一可重复读隔离级别下V1、V2的值都为1,V3的值为2。根据小测试一的思路,你可能会得出小测试二的结果为V1为1,V2为2,那么V3是多少呢?
其实正确的答案是V1为1,V2为3,V3为3。如果sessionA中的set V=V+1是set V=1+1的话,这样就丢失了sessionB更新的操作,使数据不正确,这时因为sessionB提交了,所以sessionA中的更新同一个值为当前读,为set V=2+1,所以V2为3。小测试一中读取的数据在概念中为一致性读
如果流程中把sessionB的提交事务放在sessionA的提交事务后面呢?这个时候sessionA的set V=V+1会被阻塞,直至sessionB的事务提交后才会执行,结果还是V1为1,V2为3,V3为3。

MySQL的事务隔离级别默认为可重复读,oracle的事务隔离级别默认为读提交,所以在把oracle迁移至MySQL时需要记得把MySQL的设置读提交后操作。
可重复读在事务启动时会创建一个视图,后继查询都在此视图上操作。
读提交在事务启动时也会创建一个视图,但其他事务更新操作会直接更新此视图。
读未提交直接读取数据库中最新的数据。
串行化直接进行加锁避免其他事务修改。

view1
view2
1 2

如上表格所示视图,行数据从1更新为2的过程对应视图view1到view2的过程。
读提交隔离级别下,事务启动时是view1视图,当sessionB发生更新数据后,视图view1会更新成视图view2,后续查询在view2上进行。
可重复读隔离级别下,事务启动时是view1视图,当sessionB发生更新数据后,事务还是照样读取view1视图。
可重复读隔离级别下,是怎么找到view1视图的呢?
其实这就是MVCC的功能了,事务在启动时会获得系统会分配一个按顺序递增的transaction id,然后事务在更新数据时会把这个transaction id 分配给这一行数据当做trx row_id,顺便记录undo log日志。比如上面sessionA事务在启动时拿到的transaction id为889,sessionB的transaction id为890,那么sessionB更新完后数据的trx row_id为890。在查询V2的值时,sessionA发现数据版本为890,当前自己事务id为889,所以利用undo log“回滚”显示出上一版本的数据,上一版本可以是889也可能是比889小的trx row_id,取值。

1.4、隔离级别解决脏读、不可重复读、幻读

声明一点,读未提交、读提交、可重复读、串行化隔离级别依次递增,隔离得越严实,效率就越低。
脏读

事务读取到其他事务修改后未提交的值。

不可重复读

事务在启动时读取到的值,跟事务在执行过程中重新读取到的值不一样。

幻读

事务启动后,其他事务对数据库新插入的行被本事务读取到了。幻读仅专指新插入的行

根据上述脏读、不可重复读、幻读的概念与隔离级别能做到的,我可以得出以下关系:

脏读 不可重复读 幻读
读未提交 可能 可能 可能
读提交 不可能 可能 可能
可重复读 不可能 不可能 可能
串行化 不可能 不可能 不可能

2、ACID

A.Atomicity.原子性

一个事务的操作是要么全部成功,要么全部失败。例如A给B转账100块,保证A账户会减少100块,B账户增加100块,这100块是A转过来的,不出现A账户减少了,B账户却没对应增加100块的情况。

原子性通过undo log实现,undo log记录了回滚信息,当事务失败或进行rollback时,就会根据信息回滚到操作前的样子。
当delete时,undo log会相应记录被删除数据的信息,当发生回滚时,进行insert操作。
当update时,undo log会记录更新操作的信息,当发生回滚时,进行update操作。
当insert时,undo log会记录对应的主键,当发生回滚时,进行delete操作。

C.Consistency.一致性

事务在执行前后,数据从一种合法的状态,转变成另一种合法的状态。怎么样才算合法,都是可以自己定义的,比如事务启动时A用户账户了1000块,B用户有500块,这个时候是启动时合法的状态。A用户向B用户转账100块,A用户账户余额变成900,B变成600,这是结束时合法的状态。或者平台会扣除1%的手续费,转账完成后A用户余额为899,B用户变成600,平台账户增加1块钱,这也是合法的状态。

一致性是通过原子性、隔离性、持久性来保证的。所以只有保证了AID特性,才能保证C特性。

I.Isolation.隔离性

一个事务的查询结果不会被其他事务所影响,事务之间是隔离的。例如X事务在启动时查询id=1的结果为1,X事务在没有对此记录进行修改操作的时候,多次查询结果还是为1,不管其他事务是否对此记录进行了修改。

隔离性通过MVCC实现,具体实现可以参考上面中的小测试逻辑。

D.Durability.持久性

一个事务执行完成了,所修改的数据能保存至数据库,不管宕机还是突然断电,数据库重新启动后查询到的数据为事务操作过后的数据。

持久性通过redo log实现,MySQL中有个WAL的逻辑,就是编辑数据时,会先更新redo log日志,再更新内存,最后再写磁盘。写redo log日志是一个非常快的操作,而更新完内存后,写进磁盘是很忙的。当还没写进磁盘时发生宕机等,MySQL重启后会自动去对比redo log日志与磁盘内容,把未刷进磁盘的数据刷进磁盘中,从而保证了数据的持久性。

3、扩展知识

undo log

回滚日志记录数据修改的逆向还原操作记录。例如数据值从1按顺序修改成了2、3、4。那么回滚日志就会按顺序记录:2->1,3->2,4->3

MVCC

Multi-Version Concurrency Control是MySQL数据库中的多版本并发控制,就是同一条记录在数据库中是可以存在多个版本。依靠undo log与乐观锁实现。

乐观锁

乐观地认为不会冲突,在最后需要修改数据的时候去拿一下锁认证一下就好。常见的方法有版本号控制和时间戳控制。

悲观锁

悲观的认为数据会被其他事务修改,所以在拿到数据时直接加上锁,阻止其他事务进行修改。例如for update。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 提到事务,你肯定并不陌生,和数据库打交道的时候,我们总是会用到事务。最经典的例子就是转账,你要给朋友小王转100元...
    allen成阅读 538评论 0 0
  • 事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在MySQL中,事务支持是在引擎层实现的。MySQL是一...
    花神子阅读 374评论 0 2
  • 事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在 MySQL 中,事务支持是在引擎层实现的。MySQL...
    itczl阅读 991评论 0 0
  • 十里桃花万杨柳,中原无此好风光。 众所周知,新疆有三美,美景美人和美食。 舌尖上的旅行|新疆 作为一个资深吃货的我...
    背包十年beibao10阅读 402评论 0 1
  • 最近新上了一个服务,用得是Spring Boot + MySQL技术栈。既然涉及到了MySQL,就得考虑连接池,不...
    吉不赛阅读 657评论 0 1