前言
前几年国家鼓励重要软件国产化,我们公司也赶风口,做了一个国产化数据库,该国产化数据库是基于Mysql,自己实现存储引擎的一个数据库,具体名字这里就不提了。数据库开发完成后,首次落地就在我所在的项目组投入了使用,使用过程中出现了好多问题,在解决这些问题时,我听到的最多的名词就是“锁”,到底什么是锁,我当时也一知半解。后来翻了书问了大佬,终于知道了个大概,这里做下记录。
一、基于数据库设计上的锁的概念
行锁
提到锁,我最初想到的就是一个事务将数据行锁住,不允许其他事务操作,这种锁人们称之为“行锁”,但是后来看了书之后,才明白数据库的事务是不会锁定某个数据行的,只会锁定该行数据对应的索引。所以行锁锁定的是索引。
表锁
如果update一行数据,比如,update test_table set name = 'test1' where id = 1,如果id为主键或者有索引,那么就锁定id=1这一行,如果test_table没有索引,则锁定整张表。那么表锁的意思就是锁定整张表。
页锁
在行和表之间还有一个概念叫”页“,一页可以理解为有很多行,一个表由很多页构成。当然mysql里面是没有页锁这个概念的,但是比如SQL SERVER就有这个概念。
二、锁得粒度比较
表锁 > 页锁 > 行锁
以上所讲到的锁的概念都是基于数据库设计上的,以下讲到的锁都是基于实现上的
三、基于实现上的锁的概念
这里的锁有两个概念,一个是lock,一个是latch.他们都叫锁,但是两者的含义却截然不同。
latch表示的是一种锁得时间相当短的锁,经常听说的名词有:互斥锁,读写锁。比如java中常听到的锁其实指的就是latch, 经常用到的锁工具CountDownLatch等。
lock表示的是一种作用于事务的锁,经常听说的名词有:共享锁、排他锁、意向锁。
innodb中锁的实现
mysql提供了两种锁实现,其中一种为共享锁(share lock)也就是常说的S锁,另一种为排他锁(exclusive lock)也就是常说的X锁。然后innodb扩展了一个意向锁(Intention lock),
1、共享锁
share lock: 允许事务读取一行数据。如果一个事务对一行数据添加了share lock,那么另一个事务依然可以对该行数据进行读取。
2、排他锁
exclusive lock: 允许事务删除或修改一行数据,如果一个事务对一行数据添加了exclusice lock,那么另一个事务不可以对该行进行任何操作,包括读取也不可以。
3、意向锁
intention lock:意向锁Innodb扩展的一种加锁方式,是对加锁对象进行分层加锁,如果把加锁对象看成一颗树,如果要为最下层对象加S锁,那么首先要为顶层对象加IS(意向共享锁)锁,比如要给一张表中的某一行上X锁,那么首先要分别对数据库、表、页IX锁。 如图:
意向锁的作用是为了降低表锁和行锁的冲突,加快上锁效率。 基于上图,如果事务A成功对记录r添加了X锁,那么此时数据库A、表1、页c必然成功添加了IX锁,这时事务B要对表1添加X锁,发现已经存在IX锁,由于锁不兼容,所以事务B只能等待事务A结束。
那么如果没有意向锁会怎么样呢?
事务A成功对记录r添加了X锁,此时事务B要对表1添加X锁,那么事务B肯定要判断当前表是否可以添加X锁,如何判断呢,如果没有意向锁,我理解只能通过遍历每一行,然后判断行上是否已经加锁,这样的话效率就大大的降低了。
四、mysql如何查看锁
-- mysql 8.0及以上:
SELECT * FROM performance_schema.`data_locks`; -- 查看具体的锁类型
SELECT * FROM performance_schema.data_lock_waits; -- 查看等待的锁
SELECT * FROM information_schema.`innodb_trx`; -- 事务详细信息
-- mysql5:
SELECT * FROM information_schema.`innodb_locks`;
SELECT * FROM information_schema.`innodb_lock_waits`;
SELECT * FROM information_schema.`innodb_trx`;
五、其他锁的概念
其他锁的概念都是innoDb在实现时的一些基于以上行锁或者表锁的具体实现。
1、间隙锁
间隙锁是行锁的一种实现方式。这种锁一般作用于数据交界的地方,比如A事务select * from test_table where id between 0 and 5;此时间隙锁会锁定这0-5的索引记录(id为主键或存在索引),如果此时事务B要执行update test_table set name = 'test' where id=1,那么此时事务B要等待事务A执行完毕,如果事务B要执行update test_table set name = 'test' where id=6,那么此时事务B是不需要等待事务A执行完毕的。
2、记录锁
记录锁可以理解为是广义行锁的一个具体实现。如果一个事务A对一条记录添加记录锁(行锁),另一个事务B再对行记录添加记录锁(行锁)则需要等待A事务结束。
3、临键锁(Next-key)
临键锁也是行锁的一种,具体概念我还是没太理解...,总体意思就是如果一张表使用了除主键和索引字段外的其他字段进行检索时,会触发临键锁,临键锁是一个左闭右开的区间,如果一个事务A对表的操作触发了临键锁,事务B操作的数据恰好位于临键锁的区间内,那么事务B需要等待事务A结束。 可以参考如下地址: blog.csdn.net/fofcn/artic…
4、插入意向锁
上面介绍意向锁的时候举了一个例子,如果事务A成功对记录r添加了X锁,那么此时表1上会有一个IX锁,如果此时事务B要对插入记录r1,需要加X锁,首先也要对表1添加IX锁,由于两个IX锁兼容,所以B可以对另一个记录添加X锁,此时的X锁就叫插入意向锁。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第5天,点击查看活动详情