MySQL高级 之 锁

Posted 走慢一点点

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL高级 之 锁相关的知识,希望对你有一定的参考价值。

mysql锁概述

相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁;InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

MySQL这3种锁的特性可大致归纳如下。
开销、加锁速度、死锁、粒度、并发性能
l 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
l 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
l 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

仅从锁的角度来说:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。

MyISAM表锁(偏读)

MyISAM存储引擎只支持表锁

查询表级锁争用情况

show status like 'table%';

Table_locks_immediate:产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1

Table_locks_waited:出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,没等待一次锁值加1)。此值比较高则说明存在着较严重的表级锁争用情况

MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。锁模式的兼容性如下表:

兼容性None(请求锁模式)读锁(请求锁模式)写锁(请求锁模式)
读锁(当前锁模式)
写锁(当前锁模式)

可见:
对MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;
对 MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作;

MyISAM表的读操作与写操作之间,以及写操作之间是串行的。当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。

InnoDB表锁(偏写)

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

获取InnoDB行锁争用情况

show status like 'innodb_row_lock%';

对各状态量的说明如下:

示例

通过非索引条件检索数据,InnoDB使用表级锁例子

session1session2
-
- // 等待挂起
-
- // 超时

通过索引条件检索数据,InnoDB使用行级锁例子

session1session2
-
-

索引失效 行锁变表锁

session1session2
-
- // 等待挂起

间隙锁

间隙锁(Gap Lock):锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。

间隙锁是innodb中行锁的一种,但是这种锁锁住的却不止一行数据,他锁住的是多行,是一个数据范围。间隙锁的主要作用是为了防止出现幻读,但是它会把锁定范围扩大,在某些场景下这可能会对性能造成很大的危害。

示例:如果一个间隙被事务T1加了锁,其它事务是不能在这个间隙插入记录的。

session1session2
-
-// 等待挂起

间隙锁的目的是为了防止幻读,其主要通过两个方面实现这个目的:
(1)防止间隙内有新数据被插入
(2)防止已存在的数据,更新成间隙内的数据(例如防止numer=3的记录通过update变成number=5)

innodb自动使用间隙锁的条件:
(1)必须在RR级别下
(2)检索条件必须有索引(没有索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加)

如何锁定一行

FOR UPDATE仅适用于InnoDB,且必须在交易区块(BEGIN/COMMIT)中才能生效。

select * from test_innodb where id = 1 for update;

假设有个表单products ,里面有id跟name二个栏位,id是主键。

例1: (明确指定主键,并且有此记录,row lock)
SELECT * FROM products WHERE id=’3’ FOR UPDATE;
SELECT * FROM products WHERE id=’3’ and type=1 FOR UPDATE;

例2: (明确指定主键,若查无此记录,无lock)
SELECT * FROM products WHERE id=’-1’ FOR UPDATE;

例2: (无主键,table lock)
SELECT * FROM products WHERE name=’Mouse’ FOR UPDATE;

例3: (主键不明确,table lock)
SELECT * FROM products WHERE id<>’3’ FOR UPDATE;

例4: (主键不明确,table lock)
SELECT * FROM products WHERE id LIKE ‘3’ FOR UPDATE;

以上是关于MySQL高级 之 锁的主要内容,如果未能解决你的问题,请参考以下文章

MySQL InnoDB锁机制之Gap LockNext-Key LockRecord Lock解析

MySQL高级——锁与事务

MySQL高级——锁与事务

MySQL高级——锁与事务

mysql间隙锁 转

mysql的RR下当前读和快照读不一致的情况;记录锁和间隙锁;幻读解释