为了保证数据并发访问的一致性和有效性,数据库会提供锁机制。但是锁会消耗资源,增加系统的开销。
锁的分类
按锁的粒度可分为:表级锁、行级锁、页级锁。
表级锁(MyISAM存储引擎默认使用表级锁)
表级锁会锁定整张表,可以很好的避免死锁。
表级锁根据操作不同,分为:读锁(共享锁)、写锁(排他锁)
读锁
读锁(read lock),也叫共享锁(shared lock)。
一个用户在对表进行读操作(select)时, 针对同一份数据,多个读操作可以同时进行而不会互相影响。
写锁
写锁(write lock),也叫排他锁(exclusive lock)。
一个用户在对表进行写操作(插入、删除、更新等)时,需要先获得写锁,它会阻塞其它用户对该表的所有读写操作,具备排他性。
小结
读锁和写锁
读锁会阻塞写操作,不会阻塞读操作
写锁会阻塞读和写操作
表级锁
对整张表加锁
开销小
加锁快
无死锁
锁粒度大,发生锁冲突概率大,并发性低
行级锁
行级锁的锁定颗粒度在 MySQL 中是最小的,只针对操作的当前行进行加锁,发生所重同的概率也小。
行级锁根据操作的不同,分为:读锁(共享锁 S)、写锁(排他锁 X)、意向共享锁(IS)、意向排它锁(IX)。
读锁 S
读锁(read lock),也叫共享锁(shared lock)。
允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
写锁
写锁(write lock),也叫排他锁(exclusive lock)。
允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享锁和排他锁。
意向共享锁IS
一个事务给一个数据行加共享锁时,必须先获得该表的意向共享锁,简称IS锁。
意向排他锁IX
一个事务给一个数据行加排他锁时,必须先获得该表的意向排他锁,简称IX锁。
行级锁的实现算法
行锁通过给索引树中的索引项加锁来实现,如果没有索引,InnoDB 将通过隐藏的主键索引(聚集索引)引来对记录加锁。
记录锁(Record Lock):直接对索引项加锁,属于单个行记录上的锁。
间隙锁(Gap Lock):间隙锁是一个在索引记录之间的间隙上进行锁定。
临键锁(Next-Key Lock):记录锁+间隙锁组合起来用就叫做临键锁 Next-Key Lock。 锁定一个范围,同时包含记录本身。
小结
对一行数据加锁
开销大
加锁慢
会出现死锁
锁粒度小,发生锁冲突概率最低,并发性高
页级锁(page lock)
页级锁的颗粒度介于行级锁与表级锁之间,会发生死锁。
死锁
数据库的死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。
死锁发生以后,只有部分或完全回滚其中一个事务,才能打破死锁。多数情况下只需要重新执行因死锁回滚的事务即可。
避免死锁的方式
1.如果不同程序会并发存取多个表,或者涉及多行记录时,尽量约定以相同的顺序访问表,这样可
以大大降低死锁的发生。
2业务中要及时提交或者回滚事务,可减少死锁产生的概率。
3在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率。
4对于非常容易产生死锁的业务部分,可以尝试使用升级锁粒度,通过表锁定来减少死锁产生的概
率(表级锁不会产生死锁)。