MyISAM和InnoDB存储引擎使用的锁:

  • MyISAM采用表级锁(table-level locking)。
  • InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁

表级锁和行级锁对比:

  • 表级锁: MySQL中锁定 粒度最大 的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。
  • 行级锁: MySQL中锁定 粒度最小 的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。

详细内容可以参考: MySQL锁机制简单了解一下:https://blog.csdn.net/qq_34337272/article/details/80611486
InnoDB存储引擎的锁的算法有三种:

  • Record lock:单个行记录上的锁
  • Gap lock:间隙锁,锁定一个范围,不包括记录本身
  • Next-key lock:record+gap 锁定一个范围,包含记录本身

相关知识点:

  1. innodb对于行的查询使用next-key lock
  2. Next-locking keying为了解决Phantom Problem幻读问题
  3. 当查询的索引含有唯一属性时,将next-key lock降级为record key
  4. Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生
  5. 快照读的幻读-mvcc 解决,当前读的幻读-gap 锁解决

MySQL中的锁机制?(重点掌握)

答:MySQL数据库的锁分为表级锁和行级锁。从数据库的角度看,行级锁又可以分为独占锁和共享锁

独占锁(排他锁),也称X锁(Exclusive Lock):

独占锁锁定的资源只允许进行锁定操作的程序使用,其它任何对它的操作均不会被接受。执行数据更新命令,即INSERT、UPDATE 或DELETE 命令时,MySQL会自动使用独占锁。但当对象上有其它锁存在时,无法对其加独占锁。独占锁一直到事务结束才能被释放。
在select命令中使用独占锁的SQL语句为:select … for update;

共享锁,也叫S锁(Shared Lock):

共享锁顾名思义,那就是其锁定的资源可以被其它用户读取,但其它用户不能修改。如果在select查询语句中要手动加入共享锁,那么对应的SQL语句为:select … lock in share mode

这里需要注意:
一个事务在一行数据上加入了独占锁,那么其余事务不可以在该数据行上加入任何锁。也就是说加过排他锁的数据行在其他事务种是不能修改数据的,也不能通过for update和lock in share mode锁的方式查询数据,但可以直接通过select …from…查询数据,因为普通查询没有任何锁机制。

MySQL中的死锁:

在多线程章节(第8节:Java进阶 - 高效并发编程(上))中,我们介绍了多线程为了争夺资源可能会造成死锁,也就是一种环路等待的现象。MySQL中的死锁主要是多个事务使用行级锁对某行数据加锁造成的,上一小节说了MyISAM不支持行级锁,所以MySQL中的死锁主要是在说InnoDB存储引擎的死锁。

那么MySQL的死锁该如何解决呢?

  • 如果不同事务并发存取多个表,尽量约定相同的顺序来访问表,可以降低死锁的机会
  • 在同一个事务中,尽量做到一次锁定所需要的所有资源,减少死锁的概率
  • 对于容易产生死锁的业务,可以用表级锁来减少死锁的概率

我们在来看一个关于行级锁的问题吧~

面试官:“行级锁什么时候会锁住整个表?“

InnoDB行级锁是通过锁索引记录实现的,如果更新的列没建索引是会锁住整个表的。

悲观锁与乐观锁:

从程序员的角度看,数据库中的锁又可以分为悲观锁和乐观锁。
悲观锁:利用数据库的锁机制实现,在整个数据处理过程中都加入了锁,以保持排他性。
乐观锁:乐观锁可以利用CAS实现,在操作数据的时候进行一个比较,按照当前事务中的数据和数据库表中的该数据是否一致来决定是否要执行本次操作。
我们来举例说下乐观锁的CAS实现,有如下的数据库表和数据:
[

](https://www.nowcoder.com/tutorial/10014/d744f804d1374c4b81628218937d1b17#)

  1. create table cas_test(
  2. phone varchar(32) primary key,
  3. name varchar(32)
  4. )engine=InnoDB;
  5. // 插入数据
  6. insert into cas_test values("18810101035","zhangsan");

锁机制与InnoDB锁算法 - 图1
当我们将数据更新后,会比较该行数据与数据库表中的该行数据是否一致,以此来决定是否要更新数据。

面试官:“乐观锁的ABA问题有了解吗?如何解决?“

ABA问题是指在当前事务读取该行数据时是A,经过别的事务修改成B,但是在当前事务要更新数据的时候,该行数据又被别的事务修改为A,事实上数据行是发生过改变的,存在并发问题。
ABA问题可以通过基于数据版本(Version)记录机制来解决。也就是为数据增加一个版本标识。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。根据当前事务的数据版本号和数据库中数据的版本号对比来决定是否更新数据。
与给当前数据增加一个数据版本类似,我们也可以增加基于时间戳机制来解决ABA问题,通过时间戳来记录当前数据行变化。

基于数据版本Version机制,表结构设计如下所示:

锁机制与InnoDB锁算法 - 图2

基于时间戳机制,表结构设计如下所示:

锁机制与InnoDB锁算法 - 图3