Mysql的锁

一、Mysql的读类型

1.1 一致性读

事务利用MVCC进行的读取操作称之为一致性读,或一致性无锁读,也称之为快照读。

1.2 锁定读

1.2.1 共享锁和独占锁

共享锁 : Shared Locks ,简称 S锁 。在事务要读取一条记录时,需要先获取该记录的 S锁 。
独占锁 :排他锁 , Exclusive Locks ,简称 X锁 。在事务要改动一条记录时,需要先获
取该记录的 X锁 。兼容性:
Mysql的锁_第1张图片

1.2.2 锁定读的语句

1、对读取的记录加 S锁 :SELECT ... LOCK IN SHARE MODE;

2、对读取的记录加 X锁 :SELECT ... FOR UPDATE;

1.2.3 写操作

写操作 无非是 DELETE 、 UPDATE 、 INSERT 这三种:

1、DELETE操作

获取X锁的锁定读:B+ 树中定位到这条记录的位置,获取一下这条记录的 X 锁 ,然后再执行 delete mark 操作。

2、UPDATE操作

1、未修改键值且空间未改变:在B+ 树中定位位置,然后获取一下记录的X锁,最后在原记录的位置进行修改操作。把这个定位待修改记录在 B+ 树中位置的过程看成是一个获取 X锁 的 锁定读 。
2、未修改键值且至少一个被更新的列空间变化,在B+ 树中定位位置,然后获取记录的 X锁 ,将该记录彻底删除掉(就是把记录彻底移入垃圾链表),最后再插入一条新记录。这个定位待修改记录在 B+ 树中位置的过程看成是一个获取 X锁 的 锁定读 ,新插入的记录由 INSERT 操作提供的 隐式锁 进行保护。
3、修改了该记录的键值:

则相当于在原记录上做 DELETE 操作之后再来一次 INSERT 操作,加锁操作就需要按照 DELETE 和 INSERT 的规则进行了。

二、多粒度锁

IS、IX锁是表级锁加表级别的S锁和X锁时,快速判断表中的记录是否被上锁,以避免用遍历的方式来查看表中有没有上锁的记录,也就是说其实IS锁和IX锁是兼容的,IX锁和IX锁是 兼容的。

Mysql的锁_第2张图片

三、MySQL中的行锁和表锁

3.1 其他存储引擎得锁

        对于 MyISAM 、 MEMORY 、 MERGE 这些存储引擎来说,它们只支持表级锁,而且这些引擎并不支持事务,所以使用这些存储引擎的锁一般都是针对当前会话来说的。

3.2 InnoDB存储引擎中的锁

3.2.1 InnoDB表锁

1、表级别的 S锁 、 X锁 

在对某个表执行诸如 ALTER TABLE 、 DROP TABLE 这类的 DDL 语句时,其他事务对这个表并发执行诸如 SELECT 、 INSERT 、 DELETE 、 UPDATE 的语句会发生阻塞,同理,某个事务中对某个表执行SELECT 、 INSERT 、 DELETE 、 UPDATE 语句时,在其他会话中对这个表执行 DDL 语句也会发生阻塞。这个过程是在server层使用一种称之为 元数据锁来实现的,一般情况下也不会使用 InnoDB 存储引擎自己提供的表级别的 S锁 和 X锁 。手动添加表锁:

    LOCK TABLES t READ : InnoDB 存储引擎会对表 t 加表级别的 S锁 。
    LOCK TABLES t WRITE : InnoDB 存储引擎会对表 t 加表级别的 X锁 。

2、表级别的 IS锁 、 IX锁

当我们在对使用 InnoDB 存储引擎的表的某些记录加 S锁 之前,那就需要先在表级别加一个 IS锁 ,当我们在对使用 InnoDB 存储引擎的表的某些记录加 X锁 之前,那就需要先在表级别加一个 IX锁 。 IS锁 和 IX锁的使命只是为了后续在加表级别的 S锁 和 X锁 时判断表中是否有已经被加锁的记录,以避免用遍历的方式来查看表中有没有上锁的记录。

3、表级别的 AUTO-INC锁

采用 AUTO-INC 锁,也就是在执行插入语句时就在表级别加一个 AUTO-INC 锁,然后为每条待插入记录的 AUTO_INCREMENT 修饰的列分配递增的值,在该语句执行结束后,再把 AUTO-INC 锁释放掉。这样一个事务在持有 AUTO-INC 锁的过程中,其他事务的插入语句都要被阻塞,可以保证一个语句中分配的递增值是连续的。
1、如果我们的插入语句在执行前不可以确定具体要插入多少条记录(无法预计即将插入记录的数量),比方说使用 INSERT ... SELECT 、 REPLACE ... SELECT 或者 LOAD DATA 这种插入语句,一般是使用AUTO-INC 锁为 AUTO_INCREMENT 修饰的列生成对应的值。
2、如果我们的插入语句在执行前就可以确定具体要插入多少条记录,比方说我们上边举的关于表 t 的例子中,在语句执行前就可以确定要插入2条记录,那么一般采用轻量级锁的方式对 AUTO_INCREMENT 修饰的列进行赋值。这种方式可以避免锁定表,可以提升插入性能。

3.3 InnoDB锁的内存结构

3.3.1 锁结构

满足以下条件可以创建锁结构:
1、在同一个事务中进行加锁操作 
2、被加锁的记录在同一个页面中 
3、加锁的类型是一样的 
4、等待状态是一样的

Mysql的锁_第3张图片

1、锁所在的事务信息 :不论是 表锁 还是 行锁 ,都在事务执行过程中生成,哪个事务生成了这个锁结构 ,这里就记载着这个事务的信息。

2、索引信息 :对于行锁来说,需要记录一下加锁的记录是属于哪个索引的。
3、表锁/行锁信息 :
    表锁:
    记载着这是对哪个表加的锁,还有其他的一些信息。
    行锁:
    记载了三个重要的信息:
    Space ID :记录所在表空间。
    Page Number :记录所在页号。
    n_bits : 记录页面的哪条数据被锁定
    小贴士:
    并不是该页面中有多少记录,n_bits属性的值就是多少。为了让之后在页面中插入了新记录后也不至于重新分配锁结构,所以n_bits的值一般都比页面中记录条数多一些。
4、type_mode :
这是一个32位的数,被分成了 lock_mode 、 lock_type 和 rec_lock_type 三个部分,如图所示:

Mysql的锁_第4张图片 

你可能感兴趣的:(mysql,数据库)