什么是锁?
1.1 锁的解释
计算机协调多个进程或线程并发访问某一资源的机制。
1.2 锁的重要性
在数据库中,除传统计算资源(CPU、RAM、I/O等)的争抢,数据也是一种供多用户共享的资源。
如何保证数据并发访问的一致性,有效性,是所有数据库必须要解决的问题。
锁冲突也是影响数据库并发访问性能的一个重要因素,因此锁对数据库尤其重要。
1.3 锁的缺点
加锁是消耗资源的,锁的各种操作,包括获得锁、检测锁是否已解除、释放锁等 ,都会增加系统的开销。
1.4 简单的例子
现如今网购已经特别普遍了,比如淘宝双十一活动,当天的人流量是千万及亿级别的,但商家的库存是有限的。
系统为了保证商家的商品库存不发生超卖现象,会对商品的库存进行锁控制。当有用户正在下单某款商品最后一件时,
系统会立马对该件商品进行锁定,防止其他用户也重复下单,直到支付动作完成才会释放(支付成功则立即减库存售罄,支付失败则立即释放)。
锁的类型
表锁
种类
- 读锁(read lock),也叫共享锁(shared lock):针对同一份数据,多个读操作可以同时进行而不会互相影响(select)。
- 写锁(write lock),也叫排他锁(exclusive lock):当前操作没完成之前,会阻塞其它读和写操作(update、insert、delete)。
MyISAM 特点 :
- 对整张表加锁
- 开销小
- 加锁快
- 无死锁
- 锁粒度大,发生锁冲突概率大,并发性低
结论:
- 读锁会阻塞写操作,不会阻塞读操作
- 写锁会阻塞读和写操作
建议 :MyISAM的读写锁调度是写优先,这也是MyISAM不适合做写为主表的引擎,因为写锁以后,其它线程不能做任何操作,大量的更新使查询很难得到锁,从而造成永远阻塞。
行锁
种类:
读锁(read lock),也叫共享锁(shared lock)
允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁
写锁(write lock),也叫排他锁(exclusive lock)
允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享锁和排他锁
意向共享锁(IS)
一个事务给一个数据行加共享锁时,必须先获得表的IS锁
意向排它锁(IX)
一个事务给一个数据行加排他锁时,必须先获得该表的IX锁
MYSQL 存储引擎默认锁 InnoDB
特点 :
- 对一行数据加锁
- 开销大
- 加锁慢
- 会出现死锁
- 锁粒度小,发生锁冲突概率最低,并发性高
事务并发带来的问题:
1. 更新丢失
解决:让事务变成串行操作,而不是并发的操作,即对每个事务开始---对读取记录加排他锁
2. 脏读
解决:隔离级别为Read uncommitted
3. 不可重读
解决:使用Next-Key Lock算法来避免
4. 幻读
解决:间隙锁(Gap Lock)
页锁
开销、加锁时间和锁粒度介于表锁和行锁之间,会出现死锁,并发处理能力一般(此锁不做多介绍)
如何上锁?
隐式上锁(默认,自动加锁自动释放)
select //上读锁
insert、update、delete //上写锁
显式上锁(手动)
lock table tableName read;//读锁
lock table tableName write;//写锁
解锁(手动)
unlock tables;//所有锁表
lock table teacher read;// 上读锁
select * from teacher; // session01可以正常读取
select * from teacher;// session02可以正常读取
update teacher set name = 3 where id =2;//session01报错,因被上读锁不能写操作 update teacher set name = 3 where id =2;// session02被阻塞
unlock tables;// 解锁
update teacher set name = 3 where id =2;// 更新操作成功
lock table teacher write;// 上写锁
select * from teacher; // session01可以正常读取
select * from teacher;// session02被阻塞
update teacher set name = 3 where id =2;// session01可以正常更新操作
update teacher set name = 4 where id =2;// session02被阻塞
unlock tables;// 解锁
select * from teacher;// 读取成功
update teacher set name = 4 where id =2;// 更新操作成功