MySQL锁
锁
一. 锁概述
InnoDB默认支持行级锁,但也支持表级锁
MyISAM,Memory支持表级锁
三种锁特性
1. 表级锁
用于查询为主,少量按索引条件更新
开销小,加锁快
不会出现死锁
锁粒度大,锁冲突概率高,并发度低
2. 行级锁
适用于大量按索引条件更新数据,如OLTP
开销大,加锁慢
会出现死锁
锁粒度小,锁冲突概率低,并发度高
3. 页面锁
加锁时间介于前二者之间
会出现死锁
并发度一般
二. MyISAM表锁
1. 表锁兼容性
读写互斥
2. 如何加表锁
MyISAM在select前自动加读锁,更新前自动加写锁
MyISAM总是一次性获得SQL语句的所有锁---故无死锁
3. MyISAM锁调度
读写互斥,且写请求比读请求重要
故不适用大量更新和查询应用(查询操作被永远阻塞)
避免长时间查询操作,导致饿死写请求--不要想一条SELECT搞定所有
三. 事务论
支持事务;采用行级锁
1. 事务的ACID特性
Atomicity 原子性
数据修改,要么全执行,要么全不执行
Consistent 一致性
事务开始和完成时,数据一致
Isolation 隔离性
事务不受外部并发操作影响,独立执行
Durable 持久性
事务完成后,数据修改是永久性的,系统故障也能保持
2. 并发事务问题(锁问题)
1) 更新丢失
最后的更新覆盖了其他事务所做的更新
必须完全避免
2)脏读
一个事务修改了记录,但未提交,同时另一个事务对该记录进行读取
3)不可重复读
事务再次读取之前读过的数据,该数据已改变或该记录已被删除
4)幻读
一个事务相同条件查询,发现其他事务插入了满足条件的新数据
3. 事务隔离级别
脏读、不可重复读、幻读----数据库读一致性问题,事务隔离机制来解决
1) 事务隔离方式
- 读取数据前加锁
- MVCC(multiversion concurrency control ) --多版本并发控制(或多版本数据库)
生成数据请求时间点 一致性数据快照(同一数据,多个版本)
MVCC实现InnoDB一致性非锁定读:
若读取的行正在delete,update操作,不等待行上锁释放,转去读取行的一个数据快照。如下图
2) 事务隔离级别
用以解决隔离与并发的矛盾,分为四种:
未提交读(导致脏读,很少用)
已提交读(大多数数据库默认级别
可重复读(mysql默认,无法解决幻读)
可序列化(每行加锁,导致大量超时和锁争用,很少使用)
四. InnoDB锁
1. InnoDB行锁模式及加锁方法
两种行锁:
1) 共享锁(S)
- 允许一个事务读一行,阻止其他事务获得相同数据的 排他锁
- 加锁语句:
select * from table where... LOCK IN SHARE MODE
2) 排他锁(X)
- 持X的事务可更新数据,阻止其他事务(取得相同数据集)的 共享读锁 和 排他写锁
- 加锁语句:
select * from table where...FOR UPDATE
两种意向锁(表锁):
InnoDB自动加
对更新语句,自动加X锁
普通SELECT语句,不加锁
1) 意向共享锁(IS)
事务想获得表中某几行的共享锁
事务在对数据行加S锁前,必须先取得表IS锁
2)意向排他锁(IX)
事务想获得表中某几行的排他锁
2. InnoDB行锁实现方式
- InnoDB行锁通过对索引项加锁实现
- 无索引,则通过聚簇索引加锁
- 不通过索引条件检索,InnoDB会锁定所有记录,导致大量锁冲突,效果等同于表锁
三种InnoDB锁算法
1) record lock
索引项加锁
2) gap lock
对第一条记录前,索引项之间,最后一条记录之后 的 间隙 加锁
3) next-key lock
前二者组合,对记录和前面的间隙加锁
用于范围条件查询
3. Next-Key锁
Gap
键值在条件范围内,但不存在的记录
目的
防止幻读
恢复和复制机制需要
会阻塞条件范围内键值插入,导致严重锁等待,故尽量用相等条件
例:
id={1,2,3....101}
select * from table where id>100 for update
对101,>101(间隙)加锁
五. 如何避免死锁
@其他补充