(十四)并发控制

  之前在(十三)事务处理中简单的介绍了锁系统,并且介绍了由于并发而产生的种种问题,例如脏读、幻读等,因此这里对如何解决这些问题再进行一下补充。


1、悲观锁

  在关系型数据库管理系统里,悲观并发控制是一种并发控制的方法,它可以阻止一个事务以影响其他事务的方式来修改数据。悲观锁需要使用数据库的锁机制,可以从字面理解为这种并发方式就是很悲观,每次调用数据的时候都认为同时会有其他事务在修改数据,因此每次在调用数据前都会先上锁,这样可以防止其他事务读取或修改表中的数据。

  例如:



  此处之所以会出现死锁,就是因为执行这条语句时已经使用了锁,

UPDATE tbl_name SET col_name = newValue WHERE id = x;

  因此互相调用相同的字段造成了死锁。

  悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。悲观并发控制实际上是”先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,并且会增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载,还会降低并行性,因为一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以进行处理。


2、乐观锁

  乐观锁相对于悲观锁而言,通常会假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自负责的数据。在提交数据更新之前,每个事务会先检查在读取数据后,有无其他事务再次修改了该数据。如果有,那么当前正在提交的事务会进行回滚。可以从字面理解为这种并发方式就是很乐观,每次调用数据的时候都认为其他事务不会在同时修改数据,因此不会上锁。

  在处理数据时,乐观锁并不会使用数据库提供的锁机制,通常乐观锁的实现方式是记录数据版本,即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加1。当提交更新的时候,判断当前version值是否与之前读出的version值一致,如果相同,则予以更新,否则认为是过期数据。

  例如:
  假设用户A和用户B对同一张数据表的同一个字段记录值进行修改,此时用户A和用户B从该表中读取的version值为2,用户A对记录修改结束后,version值增加1,此时该表的version字段的值是3,而用户B依然按照version值为2进行操作,不满足“提交版本必须大于记录当前版本才能执行更新”的乐观锁策略,因此,用户B的提交被驳回。这样,就避免了用户B用基于version值为2的旧数据修改的结果覆盖用户A的操作结果的可能。

  乐观并发控制多数用于数据争用不大、冲突较少的环境中,此时偶尔回滚事务的成本会低于读取数据时锁定数据的成本,因此可以获得比其他并发控制方法更高的吞吐量。


3、MVCC

  多版本并发控制(Multi-Version Concurrency Control)是为了实现数据库的并发控制而设计的一种机制。大多数的关系型数据库都支持MVCC,其突出特点是:读不加锁,读写不冲突。

  在MVCC中,读操作可以分成两类,快照读和当前读:

  • 快照读,读取的是记录的可见版本(可能是历史版本,即最新的数据可能正在被当前执行的事务并发修改),不会对返回的记录加锁;
  • 当前读,读取的是记录的最新版本,并且会对返回的记录加锁,保证其他事务不会并发修改这条记录。

  在MySQL InnoDB中,基本的SELECT操作,如

SELECT * FROM tbl_name WHERE xxxx;

  都属于快照读;而属于当前读的包含以下操作:

SELECT * FROM tbl_name WHERE xxxx LOCK IN SHARE MODE;(共享锁)
SELECT * FROM tbl_name WHERE xxxx FOR UPDATE;(排他锁)
INSERT,UPDATE,DELETE操作(排他锁)

  可以将MVCC理解为行级锁的一种妥协,它在许多情况下避免了使用锁,同时可以提供更小的开销。根据实现的不同,它可以允许非阻塞式读,在写操作进行时只锁定必要的记录。

  各个存储引擎对于MVCC的实现各不相同,下面将通过一个简化的InnoDB版本的行为来展示MVCC工作原理:
简单来说,通过为每一行记录添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。但是InnoDB并不存储这些事件发生时的实际时间,相反它只存储这些事件发生时的系统版本号。这是一个随着事务的创建而不断增长的数字。每个事务在事务开始时会记录它自己的系统版本号。每个查询必须去检查每行数据的版本号与事务的版本号是否相同。

  以下是在默认隔离级别REPEATABLE READ下,MVCC具体是怎样实现的:

  • SELECT:
      InnoDB只查找版本早于(包含等于)当前事务版本的数据行。这保证了不管是事务开始之前,或者事务创建时,或者修改了这行数据的时候,这行数据是存在的;这行数据的删除版本必须是未定义的或者比事务版本要大,这可以保证在事务开始之前这行数据没有被删除。
      符合这两个条件的行可能会被当作查询结果而返回。

  • INSERT:
    InnoDB为这个新行记录当前的系统版本号。

  • DELETE:
    InnoDB将当前的系统版本号设置为这一行的删除ID。

  • UPDATE:
    InnoDB会写一个这行数据的新拷贝,这个拷贝的版本为当前的系统版本号。它同时也会将这个版本号写到旧行的删除版本里。


4、MVCC与乐观锁的区别

  在了解了MVCC的实现机制后可能会感觉与乐观锁中使用版本号加锁有相似之处,实际上MVCC可以保证不阻塞地读到一致的数据。但是,MVCC并没有对实现细节做约束,在InnoDB引擎下是只对读无锁,写操作仍是上锁的悲观并发控制,这也意味着,InnoDB中只能见到因死锁和不变性约束而回滚,而不会出现因为写冲突而回滚的现象;MVCC对数据表中的每行数据只保留一份,在更新数据时上行级锁,同时将旧版数据写入undo log;数据表和undo log中行数据都记录着事务ID,在检索时,只读取来自当前已提交的事务的行数据。这种额外的记录所带来的结果就是对于大多数查询来说根本就不需要获得一个锁。MVCC只是简单地以最快的速度来读取数据,确保只选择符合条件的行。但其缺点也正是存储引擎必须为每一行存储更多的数据,做更多的检查工作,处理更多的善后操作。


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

推荐阅读更多精彩内容