数据库锁相关

MVCC

MVCC,即Multi-Version Concurrency Control, 多版本并发控制,是伴随着事务的需求而产生的设计思想,主要用来支持事务的并发操作、事务回滚等特性。

innoDB的MVCC实现是基于undoLog,通过表记录的隐藏字段实现多版本控制。
1)表隐藏字段:
3部分,最后事务id(DB_TRX_ID)6字节,回滚段(DB_ROLL_PTR)7字节,递增记录id(DB_ROW_ID)6字节,再加上一个记录删除delete标记。
2)undoLog
insert类型的操作undoLog会记录undo_no,table id,数据唯一键的信息,事务id。
update类型的操作undoLog会记录undo_no,table id,数据唯一键的信息,字段修改前的值,旧记录事务id,事务id。

mysql的锁

mysql的锁分为行级锁和表级锁。

  1. 行级锁:innoDB引擎实现。分为共享锁(读锁,S锁)和排它锁(写锁,X锁,独占锁)。

共享锁的特点是多个事务可以同时加读锁,但是不能加写锁。

显示加读锁:
select ... lock in share mode;

隐式加读锁:下面这种情况比较隐蔽,table_b会被加读锁,确切的说是间隙锁,所谓间隙锁就是锁住id为0到当前查询的最后一条记录的id的范围,不管这个范围中实际上有没有记录。由于select * 没有具体条件,这里innoDB会认为范围无限大,就变成table_b整个表都锁住了。
insert into table_a select * from table_b;

排他锁的特点是其他事务不能读也不能写。

update/delete/select ... for update;

关于间隙锁单记录锁

单记录锁就是锁定一行数据的锁。
innoDB对间隙锁的具体实现是使用了next-key锁
next-key锁是单记录锁和间隙锁的组合用法,锁定的是一个范围。具体会锁住查询过程中所有遍历过的数据和数据之间的间隙
next-key的查询规则具体会一直遍历找到需要查询的数据,如果查询条件是未加索引的字段,则会全表扫描,导致全表被被锁。
select * from table_a where pay = 3 for update; // pay没加索引导致全表被加了锁
特例
1)使用唯一特性的字段查询不会使用间隙锁。插入的时候包含唯一字段也会转为单记录锁。
2)如果事务隔离级别降级为读已提交(read commited,RC)则间隙锁失效。

插入意向锁
insert操作的时候加的锁。插入意向锁也是一种间隙锁,具体是指在插入之前先设置间隙锁
一个典型的例子就是当前一个事务使用非主键作为条件update操作的时候,后一个事务insert会被阻塞,影响到了并发效率。如果两个事务都先不通过索引update然后insert就会出现死锁。

总之,innoDB加锁默认都是使用next-key锁,锁定的是一个范围,如果sql写法不注意,就会锁住意料之外的行,影响到并发事务效率,甚至死锁。所以我们更新和查询都要尽量使用主键和索引。

Predicate Lock
因为next-key锁对多维空间列的支持不好,innoDB又提供了专门的Predicate Lock。大致思想就是通过锁查询条件而不是锁记录来达到目的。

  1. 表级锁:表级锁是由mysql服务实现的。

读锁(LOCK_S锁):
lock table tablename read;
写锁(LOCK_X锁):
lock table tablename write;

通常上述方式一般不会在生产环境使用。因为加上去了除了使用写琐(手动释放),加了LOCK_X锁,表数据读写操作就全部禁止了。加表锁的时候也并不知道有没有行级锁的事务操作。

为了解决这种场景,让表级锁和行级锁共存,mysql还特意提供了意向共享锁(IS)意向互斥锁(IX),类似于注册,这样加表锁的时候就不用全表扫描是否当前表有事务加行级锁了。

意向共享锁(IS)
事务想获得行级共享锁,需要先在表上加意向共享锁

意向互斥锁(IX)
事务想获得行级互斥锁,需要先在表上加意向互斥锁

X(表写锁)S(表读锁)IX(意向互斥锁)IS(意向共享锁)

表级加锁总的来看还是比较繁琐,表最好还是设计的时候索引字段什么的考虑的全面点。

表的自增锁

这是一种特殊的表级锁,自动模式(innoDB默认选项)中,自增序列在执行sql的时候就计算好了行数(如果是未知行数,则自动转为传统模式--加表级锁,insert结束后释放),然后释放掉,自增过程并不受事务控制,2个并发的事务中自增序列也会依次排列,不会出现冲突,但是如果前一个事务rollback,则那个事务加的数据对应自增序列就会丢掉,导致整个表的自增序列出现不连续。

innoDB对事务模型的支持

读未提交:直接读行记录,不管隐藏字段有什么信息。

读已提交:读行记录,如果发现最新记录的事务id未提交,则根据回滚段找到undo日志,去读取上一个版本的数据。

可重复读(mysql默认事务隔离级别):只关心自己事务id对应的数据,如果发现当前记录的事务版本不对,则通过回滚段找到undoLog去读取跟自己事务版本一致的数据。
select读取的时候会先生成一个read-view快照,这个快照只存放当前事务id版本和以前版本的记录,事务过程中就算有别的事务update提交了,也不会影响到快照。通过这种方式实现了可重复读。

快照只适用于select读的事务,如果是update操作则会实时读最新记录,从而数据结果集不一致,解决办法是先加间隙锁select...for update,这样事务结束之前其他事务想操作是成功不了的。通常幻读并不会影响数据update数据,所以我们通常可以忍受,这时候就要考虑一定要利用id或者索引,减少不必要的阻塞。

串行化:串行化的原理其实还是利用了间隙锁,默认加了读锁,自然写锁就申请不到只能等着。所谓串行化并不是严格事务部分情况必须一个一个串行执行。

几个案例

  1. 多事务并发insert导致的死锁现象

1)3事务同时insert记录的时候,假设都包含一个唯一字段并且同名。

2)因为唯一键,只会使用单记录锁,并且先加读锁去查询有没有,然后才能加写锁插入。

3)第一个事务执行中途callback了,此时事务2和事务3都加了读锁(读锁不互斥),但是没办法加写锁,因为需互相等对方释放读锁,但是读锁的释放需要写操作完成即写锁释放。死锁产生。

如果第一个事务成功提交,则不会出现死锁,因为后面的事务读操作就会发现唯一键冲突。
mysql针对这种情况会主动让一个事务报错,退出事务,这时另一个事务就能操作成功。

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

推荐阅读更多精彩内容