一,按照对数据操作的锁粒度(锁级别)来分:行级锁,表级锁,页级锁
MyISAM和MEMORY采用表级锁(table-level locking)
BDB采用页面锁(page-level locking)或表级锁,默认为页面锁
InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁
1. 行级锁
(1). 描述
行级锁是mysql中锁粒度最细的一种锁。表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突,其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁。
(2). 特点
开销大,加锁慢,会出现死锁。发生锁冲突的概率最低,并发度也最高。
其实行级锁和页级锁之间还有其他锁粒度的锁,就是间隙锁和临键锁。
InnoDB有三种行锁的算法:
1. Record lock(记录锁):单个行记录上的锁。这个也是我们日常认为的行锁。
2. Gap Lock(间隙锁),锁定一个范围,但不包括记录本身(只不过它的锁粒度比记录锁的锁整行更大一些,他是锁住了某个范围内的多个行,包括根本不存在的数据)。GAP锁的目的是,为了防止同一事务的两次当前读,出现幻读的情况。该锁只会在隔离级别是RR或者以上的级别内存在。间隙锁的目的是为了让其他事务无法在间隙中新增数据。
3. Next-Key Lock(临键锁):它是记录锁和间隙锁的结合,锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。next-key锁是InnoDB默认的锁 。
上面这三种锁都是排他锁(X锁)
next-key lock的效果相当于一个记录锁加一个间隙锁。当next-key lock加在某索引上,则该记录和它前面的区间都被锁定。
2. 表级锁
(1). 描述
表级锁时mysql中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少。被大部分mysql引擎支持。最常使用的MyISAM和InnoDB都支持表级锁定,表级锁分为表共享读锁(共享锁)与表独占写锁(排他锁)。
(2). 特点
开销小,加锁快,不会出现死锁。发生锁冲突的概率最高,并发度也最低。
LOCK TABLE my_table_name READ; 用读锁锁表,会阻塞其他事务修改表数据。
LOCK TABLE my_table_name WRITE; 用写锁锁表,会阻塞其他事务读和写。
MyISAM在执行查询语句(select)前,会自动给涉及的所有表加读锁,在执行更新操作(update,delete,insert等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用lock table命令给MyISAM表显式加锁。
但是在InnoDB中如果需要表锁就需要显式地声明了。
3. 页级锁
(1). 描述
页级锁是Mysql中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,冲突多,行级锁速度慢,冲突少。因此,采用了折中的页级锁,一次锁定相邻的一组记录。BDB 支持页级锁。
(2). 特点
开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般。
二,按照锁的共享策略来分:共享锁,排他锁,意向共享锁,意向排他锁
共享锁和排他锁在Mysql中具体的实现就是读锁和写锁
读锁(共享锁):Shared Locks(S锁),针对同一份数据,多个读操作可以同时进行而不会相互影响
写锁(排他锁):Exclusive Locks(X锁),当前写操作没有完成前,它会阻断其他写锁和读锁
IS锁:意向共享锁,Intention Shared Lock,当事务准备在某条记录上加S锁时,需要先在表级别加一个IS锁
IX锁:意向排他锁,Intension Exclusive Lock,当事务准备在某条记录上加X锁时,需要先在表级别加一个IX锁
IS、IX锁是表级锁,它们的提出仅仅为了在之后加表级别的S锁和X锁时可以快速判断表中的记录是否被上锁,以避免用遍历的方式来查看表中有没有上锁的记录。就是说当对一个行加锁之后,如果有打算给行所在的表加一个表锁,必须先看看该表的行有没有被加锁,否则就会出现冲突。IS锁和IX锁就避免了判断表中行有没有加锁时对每一行的遍历。直接查看表有没有意向锁就可以知道表中有没有行锁。
注意:如果一个表中有多个行锁,它们都会给表加上意向锁,意向锁和意向锁之间是不会冲突的。申请意向锁的动作是数据库完成的,就是说,事务A申请一行的行锁的时候,数据库会自动先开始申请表的意向锁,不需要我们程序员使用代码来申请。
总结:为了实现多粒度锁机制(白话:为了表锁和行锁都能用)
csnd当然,这四种锁都属于悲观锁
意向锁之间都不会发生冲突,排他锁跟谁都冲突
三,从加锁策略上分:乐观锁和悲观锁
1. 悲观锁认为对于同一个数据的并发操作,一定是会发生修改的(或者增删改多,查少),哪怕没有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观的认为,不加锁的并发操作一定会出问题。
2. 乐观锁则认为对于同一数据的并发操作,是不会发生修改的(或者增删改少,查多)。在更新数据的时候,会采用不断尝试更新的方式来修改数据。也就是先不管资源有没有被别的线程占用,直接申请操作,如果没有发生冲突,那就操作成功,如果产生冲突,有其他线程已经在使用了,那么就不断的轮询。乐观的认为,不加锁的并发操作没有问题。就是通过记录一个数据历史记录的多个版本,如果修改完之后发现有冲突再将版本返回到没修改的样子。乐观锁就是不加锁,好处就是减少上下文切换,坏处就是浪费CPU时间。
四、其他:自增锁
自增锁(AUTO-INC锁)
自增锁是一种特殊的表级锁,主要用于事务中插入自增字段,也就是我们最常用的自增主键id。通过innodb_autoinc_lock_mode参数可以设置自增主键的生成策略。防止并发插入数据的时候自增id出现异常。
当一张表的某个字段是自增列时,innodb会在该索引的末位加一个排它锁。为了访问这个自增的数值,需要加一个表级锁,不过这个表级锁的持续时间只有当前sql,而不是整个事务,即当前sql执行完,该表级锁就释放了。其他session无法在这个表级锁持有时插入任何记录。
原文链接:https://blog.csdn.net/cy973071263/article/details/105188519
网友评论