0
点赞
收藏
分享

微信扫一扫

Mysql锁

Mysql锁

介绍

  • 按照锁的粒度来说,mysql主要包含三种类型的锁机制

全局锁:锁的是整个database,由mysql的sql layer层实现的

表级锁:锁的是某张表,由mysql的sql layer层实现的

行锁:锁的是某行数据,也可能锁定行之间的间隙。有某些存储引擎实现,比如INNODB

  • 按照锁的功能来说分为:共享读锁和排他写锁
  • 按照锁的实现方式分为:悲观锁和乐观锁(使用某一版本列或者唯一列进行逻辑控制)
  • 表级锁和行级锁的区别:

表级锁:开销小,加锁快,不会出现死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低

行级锁:开销大,加锁慢,会出现死锁,锁定粒度最小,发生锁冲突的概率最低,并发度最高

表级锁

由mysql sql layer层实现

  • Mysql的 表级锁有两种

一种是表锁

一种是元数据锁(meta data lock mdl)

  • 表锁有两种表现形式

表共享读锁:(table read lock)

表独占写锁:(table write lock)

  • 手动加锁

lock table 表名 read/write

  • 查看锁情况

show open tables

  • 删除锁

unlock tables

MDL

元数据锁

MDL不需要显式使用,在访问一个表的时候会被自动加上,MDL的作用是,保证读写的正确性,你可以想象,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做了变更,删除了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的

因此,在mysql5.5版本中引入了MDL,当对一个表做增删改查操作的时候,加MDL读锁,当要对表做结构变更操作的时候,加MDL写锁

  • 读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查
  • 读写锁之间,写锁之间是互斥的,用来保证变更表结构操作的安全性,因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行

行级锁

Mysql的行级锁,是由存储引擎来实现的,利用存储引擎锁住索引项来实现的

  • INNODB的行级锁,按照锁定的范围来说,分为三种:

记录锁(Record Locks):锁定索引中一条记录

间隙锁(Gap Locks):要么锁住索引记录中间的值,要不锁住第一个索引记录前面的值或者最后一个索引记录后面的值

Next-key Locks:是索引记录上的记录锁和索引之间的间隙锁的组合

  • INNODB的行锁,按照功能来说,分为两种:RR

共享锁:允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁

排它锁:允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁

对于UPDATE, DELETE和INSERT语句,INNODB会自动给涉及数据集加排它锁

对于普通的SELECT语句,INNODB不会加任何锁

手动加共享锁:

select * from table_name where .... LOCK IN SHARE MODE

手动加排它锁:

select * from table_name where ... FOR UPDATE

  • INNODB也实现了表级锁,也就是意向锁,意向锁是mysql内部使用,不需要用户干预

意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁

意向排它锁(IX):事务打算给数据行加行排它锁,事务在给一个数据行加排它锁前必须先取得该表的IX锁

  • 意向锁和行锁可以共存,意向锁的主要作用是为了全表更新数据时的性能提升,否则在全表更新数据时,需要先检索该表是否某些记录上面有行锁


共享锁(s)

排他锁(X)

意向共享锁(IS)

意向排它锁(IX)

共享锁(s)

兼容

冲突

兼容

冲突

排他锁(X)

冲突

冲突

冲突

冲突

意向共享锁(IS)

兼容

冲突

兼容

兼容

意向排它锁(IX)

冲突

冲突

兼容

兼容

  • INNODB行锁是通过给索引上的索引项加锁来实现的,因此INNODB这种行锁实现特点意味着:只有通过索引条件检索的数据,INNODB才是用行级锁,否则,INNODB将使用表锁

行读锁实例

session1:

BEGIN; SELECT id,name FROM userinfo WHERE id = 1 lock in SHARE MODE;##加读锁 ROLLBACK; SHOW STATUS LIKE 'innodb_row_lock%'; ##展示锁状态

session2:

UPDATE userinfo SET name = '213123' where id = 2; ##可以执行 UPDATE userinfo SET name = '213123' where id = 1; ##等待释放锁

行读锁升级为表锁实例

session1:

BEGIN; SELECT id,name FROM userinfo WHERE name = 'wangwu' lock in SHARE MODE;##加读锁 ROLLBACK;

session2:

UPDATE userinfo SET name = '213123' where id = 2; ##等待释放锁

行写锁

session1:

BEGIN; SELECT id,name FROM userinfo WHERE id = 1 for update;##加写锁 ROLLBACK;

session2:

SELECT id,name FROM userinfo WHERE id = 1; ## 可以访问 SELECT id,name FROM userinfo WHERE id = 1 lock in SHARE MODE;##加读锁,阻塞,等待session1释放

间隙锁

表中没有id=4的数据

session1:

BEGIN; SELECT id,name FROM userinfo WHERE id > 2 AND id < 5 lock in SHARE MODE; ROLLBACK;

session2:

INSERT INTO userinfo(id,name,age) VALUES(4,'123132123',33);##阻塞,等待session1释放 UPDATE userinfo SET name = '213123123' where id = 3;;##阻塞,等待session1释放

举报

相关推荐

0 条评论