【MySql学习笔记】MySql锁机制
什么是锁
锁是计算机协调多个进程或者线程并发访问某一资源的机制(避免争抢资源)。
InnoDB锁类型
MySql数据库的锁分为表级锁和行级锁,从数据库(InnoDB存储引擎)的角度来看,行级锁又可以分为独占锁和共享锁。
-
表锁:操作时,会锁住整个表。
-
行锁:操作时,会锁住整行数据。
- InnoDB行级锁使用过锁索引记录实现的,如果更新的列没创建索引是会锁住整个表的。
- 表中没有索引的时候会锁住整个表。
- 尽可能让所有数据检索都能通过索引来完成,避免无索引行锁升级为表锁。
- 合理设计索引,尽量缩小锁的范围。
- 尽量减少索引条件和索引范围,避免间隙锁。
- 一次不要操作太多的表,减少锁定的资源和时间长度。
-
独占锁(排他锁,X锁,写锁)
- 独占锁锁定的资源只允许持有锁的程序使用,其他任何的程序都不能对这些资源访问。
- 在select命令中使用独占锁的Sql语句是:select……for update
-
共享锁(S锁,读锁)
- 锁定的资源可以被其他程序读取,但是其他程序无法修改被锁定的资源。
- 在select命令中使用共享锁的Sql语句是:select……lock in share mode
MySql锁机制
MySql数据库的锁分为表级锁和行级锁,行锁又分为记录锁、间隙锁和临键锁。
-
表锁
-
行锁
-
记录锁(Record Lock):对于单个行记录上锁,总是锁住索引记录。
- select * from user where id = 1 for update
- id必须是唯一索引列或者主键列,否则就会升级为临键锁
- 此时其他的程序无法访问当前这条记录
-
间隙锁(Cap Lock):锁定一个范围,但是不包含记录本身;只对于那些"间隙"上锁。
- age:10 40 70 100
- select * from user where age = 60/select * from user age > 40 and age < 70
- age是非索引列的时候,上面的Sql对(4, 7)加了锁
-
临键锁(Next-Key Lock):Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身;当我们使用范围条件检索数据,并且请求共享或者排他锁时,InnoDB会给符合条件的已经存在的数据加锁,对于键值在条件范围内但是不存在的记录,叫做"间隙",InnoDB会对这个"间隙"也上锁,这种锁机制就是临键锁。
- age:10 40 70 100
- select * from user where age > 50 and age < 90
- age是非索引列的时候,上面的Sql对(40,70]和(70,100]
悲观锁与乐观锁
悲观锁:保证程序串行运行,利用数据库的锁机制实现,在整个数据处理过程中都加入了锁,以保证排他性。
乐观锁:保证程序并发运行,乐观锁可以使用CAS实现,在操作数据的时候进行一个比较,按照当前事务中的数据与数据库中的数据是否一致来决定是否要执行本次操作。
- 如果按照乐观锁那种方式进行对比,就会产生ABA问题。
-
ABA问题:当前事务读取该行数据是A,别的事务将其修改为B,但是当当前事务准备更新数据的时候,另外的事务又将这个数据修改为了A,此时数据其实已经被修改过了,存在并发问题。
-
解决一:在数据库表中添加一个字段version来解决,为数据库增加一个版本标识。在读取数据的时候,将版本号一起读出,更新数据的时候,对这个版本号加一,最后根据当前事务的数据版本号和数据库中的数据版本号进行对比来决定是否要更新数据。
-
解决二:增加基于时间戳机制来解决ABA问题,通过时间戳来记录当前数据行变化。
-