MYSQL 锁

什么是锁?

锁是数据库系统区别于文件系统的一个关键特性。锁机制用于管理对共享资源的并发访问,提供数据的完整性和一致性。

 MySQL 不同的存储引擎支持不同的锁机制,MyISAM 和MEMORY 存储引擎采用的是表级锁(talbe-level locking);

BDB存储引擎采用的是页面锁(page-level locking),但是也支持表级锁,InnoDB存储引擎即支持行级锁(row-level locking),也支持表级锁,但是默认情况下是采用行级锁。

  • 表级锁:开销小,加锁快;不会出现死锁;锁定颗粒度大,发生锁冲突的概率最高,并发度低。
  • 行级锁:开销大,加锁慢;会出现死锁;锁定颗粒度小,发生锁冲突的概率最低,并发度也最高。
  • 页面锁:开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定颗粒度介于表锁和行锁之间,并发度一般。

2PL 两阶段锁定协议

InnoDB 采用的是两阶段锁定协议,在事务的执行过程中,只有 COMMIT 和 ROLLBACK 是解锁阶段,其余过程都是加锁阶段,并且所有的锁都会在同一时刻释放。即同一个事务内不管需要对多少个数据项加锁,那么所有的加锁操作都只能在同一个阶段完成,在这个阶段内,不允许对已加锁的数据项进行解锁操作,即加锁和解锁操作不能交叉进行(同一个事务内)。主要用于单机事务中的一致性与隔离性。

MySQL表级锁

MySQL表级锁有两种模式:表共享读锁(Tbale Read Lock)和表独占写锁(Table Write Lock)。

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

如下图:当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作,其他线程的读写操作都会等待,直到锁被释放为止。

MyISAM在执行查询语句(SELECT)之前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE,DELECT,INSERT等)前,会自动给涉及的表加写锁,这个过程不需要用户干预。

InnoDB 的行锁

InnoDB实现了以下两种类型的行锁:

  • 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。
  • 排它锁(X):允许获得排它锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排它锁。 

另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。

  • 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先去的该表的IS锁。
  • 意向排它锁(IX):事务打算给数据行加行排它锁,事务在给一个数据行加排它锁前必须先获得该表的IX锁。

  如果一个事务请求的锁模式与当前的锁兼容,InnoDB就会将请求的锁授予该事务,反之,如果两者不兼容,该事务就要等待锁释放。意向锁是InnoDB自动加的,不需要用户干预,对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及的数据集加排它锁(X);对于普通的SELECT语句,InnoDB不会加任何锁。

 事务可以通过以下语句显示给记录集加共享锁或排它锁:

  • 共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE.
  • 排它锁(X):SELECT * FROM table_name WHERE ... FORUPDATE。

用SELECT ... IN SHARE MODE获得共享锁,主要用在需要对数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE 和 DELETE 操作。但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT ...FOR UPDATE 方式获得排它锁。

 

行锁的三种实现

InnoDB行锁是通过给索引上的索引项加锁来实现的,如果没有索引,InnoDB将通过隐藏的聚簇索引来对记录加锁。

  • Record Lock: 单个行记录上的锁。
  • Gap Lock:间隙锁,锁定一个范围,但不包括记录本身,防止间隔中被其他事务插入。
  • Next-Key Lock: Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身,防止幻读。

InnoDB这种行锁实现特点意味着:如果不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,实际效果跟表锁一样。

几个加锁例子:

从上面例子可以看出session1只给一行加了排它锁,但是session2在请求其他行的排他锁时,却出现了锁等待。原因就是在没有索引的情况下,InnoDB会对所有的记录都加锁。

2)InnoDB存储引擎的表在使用索引时使用行锁的例子

 

3)InnoDB存储引擎使用相同索引键的阻塞例子

由于MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果使用相同的索引键,是会出现锁冲突的。

4)InnoDB存储引擎使用不同索引键的阻塞例子

当表中有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。

5)即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比如对一些很小的表,他就不会使用索引,这种情况下InnoDB也会对所有记录加锁。

Next-Key 锁

当我们用范围条件而不是相等条件检索数据,并请求共享或排它锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个间隙加锁,这种锁机制就是所谓的Next-Key锁。

InnoDB使用Next-Key锁的目的,一方面是为了防止幻读,满足相关隔离级别的要求。另一方面,是为了满足其回复和复制的需要。很显然在使用范围条件检索并锁定记录时,InnoDB这种加锁机制会阻塞符合条件范围内键值的并发插入,这往往会造成严重的锁等待。

特别说明:InnoDB除了通过范围条件加锁时使用Next-Key锁外,如果使用相等条件请求给你一个不存在的记录加锁,InnoDB也会使用Next-Key锁。

各种SQL到底加了什么锁?

一、普通select

(1)在读未提交(Read Uncommitted),读提交(Read Committed, RC),可重复读(Repeated Read, RR)这三种事务隔离级别下,普通select使用快照读(snpashot read),不加锁,并发非常高;

(2)在串行化(Serializable)这种事务的隔离级别下,普通select会升级为select ... in share mode;

二、加锁select

加锁select主要是指:

  • select ... for update

  • select ... in share mode

(1)如果,在唯一索引(unique index)上使用唯一的查询条件(unique search condition),会使用记录锁(record lock),而不会封锁记录之间的间隔,即不会使用间隙锁(gap lock)与临键锁(next-key lock);

举个栗子,假设有InnoDB表:

t(id PK, name);

 

表中有三条记录:

1, shenjian

2, zhangsan

3, lisi

SQL语句:

select * from t where id=1 for update;

只会封锁记录,而不会封锁区间。

(2)其他的查询条件和索引条件,InnoDB会封锁被扫描的索引范围,并使用间隙锁与临键锁,避免索引范围区间插入记录;

三、update与delete

(1)和加锁select类似,如果在唯一索引上使用唯一的查询条件来update/delete,例如:

update t set name=xxx where id=1;

也只加记录锁;

(2)否则,符合查询条件的索引记录之前,都会加排他临键锁(exclusive next-key lock),来封锁索引记录与之前的区间;

(3)尤其需要特殊说明的是,如果update的是聚集索引(clustered index)记录,则对应的普通索引(secondary index)记录也会被隐式加锁,这是由InnoDB索引的实现机制决定的:普通索引存储PK的值,检索普通索引本质上要二次扫描聚集索引。

四、insert

同样是写操作,insert和update与delete不同,它会用排它锁封锁被插入的索引记录,而不会封锁记录之前的范围。

同时,会在插入区间加插入意向锁(insert intention lock),但这个并不会真正封锁区间,也不会阻止相同区间的不同KEY插入。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值