MySQL事务隔离级别及实现原理

一. MySQL数据库的事务隔离级别

  • 说起事务隔离级别之前,先了解一下几种数据的一致性问题:1. 脏读:a事务读取了b事务还未提交的更新数据,然后b事务回滚,导致数据不一致。2. 重复读:a事务多次读取同一条数据,b事务在a事务多次读取中间修改了数据,倒是a多次读取的数据不一致,出现不可重复读问题。3. a事务多次读取同一条数据,b事务在a事务多次读取中间插入一条了数据,a可能会出现突然读取到新的数据,也可能没有读到,然后插入的时候出现冲突,出现幻读。
  • MySQL数据库一共提供了四种数据中间的隔离级别,其中RU因为并发安全性太低一般都不会使用。而SER又因为不适用MVCC而退化为完全使用锁控制并发,导致性能非常差,一般也不会使用。
事务隔离级别 脏读 不可重复读 幻读 备注
read-uncommitted(RU)
read-committed(RC)
read-repeatable(RR)
serializable(SER)

二. 事务隔离级别的实现原理

  • MySQL事务的隔离级别依赖于MVCC的实现,因此在讲事务隔离原理之前,会先说一下我对MVCC的理解。MVCC((Multi-Version Concurrency Control)通过将数据存储为多个版本,根据不同的数据一致性要求,读取不同的版本。同时将数据库的读写锁分离,可以做到读不影响写,写不影响读,大大提高了数据库的并发性能。
  • MySQl是一个按行存储的数据库,同时每一行数据在经过多次修改之后会存储成多个版本,如下图:


    数据库行多个版本存储.png

    数据库中的数据会存在多个版本,Hbase也用这种方式存储Cell中的数据。同时版本和版本之间形成一个单向链表,每一行还存储了这个版本对应的事务id。这样做有两个好处:1. 数据可以根据数据一致性需求选择要展示的数据版本。2.在事务需要回滚时,数据库可以随意回滚到之前版本的数据。

  • 每当我们创建一个事务,MySQL都会把这个事务存储下来,如下图:


    事务存储数据结构.png

    其中我们比较关系的是read_view,我把它理解为查询视图。read_view里保存了当前数据库所有活跃的事务,并把这些事务按照提交顺序组织成已个单向链表,链表头为up_trx_id,链表尾是low_trx_id。因此,我们如果相判断某一行数据的某一个版本对当前事务是否可见,只需要将此行所在的事务id跟read_view中的事务id进行比对,根据数据一致性要求,选在是否展示。

  • 了解了数据库数据存储结构和事务存储结构之后,我们就可以聊聊四种隔离级别的实现方式:
  1. Read-Uncommited(RU)
    RU只添加了写写锁,保证修改数据和插入不会出现数据安全问题,会出现脏读,此隔离级别基本不会使用。

  2. Read-Conmmited(RC)
    RC,顾名思义,如果同时存在a和b两个事务。那么a中是没办法读到b事务未提交的修改数据的。RC修改和写入数据也是通过写写锁保证的。读操作通过MVCC实现。a事务每次在读取数据时,都会更新read_view,read_view中又存储了当前已经开启但是还未提交的事务id,因此要判断某一行数据是否可见,只需要判断数据版本对应的是事务tx-id是否在read_view中,或者tx-id>low_trx_id。RC可以避免出现脏读。

  3. Repeatable-Read(RR)
    RC数据库隔离级别下,事务中的每次查询都会更新read_view获得最新的读取视图,解决了脏读问题。但是额外带来的问题就是每次读取视图的变化,也可能导致同一个事务内对同一条数据的读取结果不一致。因此,在RR隔离级别下,每次开启事务后,read_view就不在变化,这样可以保证同一个事务内,多次读取的数据都保持一致。但是RR隔离级别仍然存在幻读现象,因为多次读的结果虽然一致,但是并不代表数据库实际的数据存储没发生变化。
    MVCC并发控制中,读操作主要分为两类:1. 快照读。2. 当前读。快照读,读取的是数据的历史版本,因为版本有多份,可以提高并发量。当前读,读取的是数据的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。
    以Inodb为例,哪些操作是快照读,哪些操作是当前读呢?
    快照读:
    select * from table where ?;
    当前读:
    select * from table where ? lock in share mode;
    select * from table where ? for update;
    insert into table values (…);
    update table set ? where ?;
    delete from table where ?;
    因此,在RC和RR数据隔离级别下,所有的update和insert操作都属于当前读,读取数据的最新版本。当然这样还不能解决幻读问题,RR隔离级别下,同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),从而保证不存在幻读现象。

  4. Serializable
    Serializable隔离级别下,数据库不再使用MVCC并发控制,完全使用共享锁和排他锁保证数据一致性。Serializable隔离级别下,读写冲突,因此并发度急剧下降,在MySQL/InnoDB下不建议使用。

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

推荐阅读更多精彩内容