1、锁的概念

锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源(如 CPU、RAM、I/O等)的争用以外,数据也是一种共享的资源。如何保证数据并发访问的一致性、 有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。 因此,锁对数据库而言显得尤其重要,也更加复杂。

相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。按照锁的粒度来划分,可以分为表锁、行锁和页锁。
image.png

2、MyISAM的表锁

MyISAM存储引擎只支持表锁。

在 执行查询操作(select)前, 会自动给涉及的所有表加读锁;

在 执行更新操作(insert、update、delete等)前, 会自动给涉及的所有表加写锁。
image.png

说明:
1)MyISAM表的读操作,不会阻塞其他用户对相同表的读操作,但会阻塞对相同表的写操作;
2)MyISAM表的写操作,会阻塞其他用户对相同表的读操作、写操作;
3)MyISAM表的读、写操作之间,以及写操作之间是串行的。

3、InnoDB的行锁

InnoDB存储引擎既支持行锁,也支持表锁,但默认情况下是采用行锁。
InnoDB的行锁是通过锁定索引项来实现的,而不是锁定物理行记录。InnoDB的锁,与索引、事务的隔离级别有关。
InnoDB的锁类型有很多种,这也是需要我们重点掌握的。
image.png
参考https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-record-locks

4、 测试数据

  1. create table bank_myisam(
  2. id int not null auto_increment primary key,
  3. name varchar(30) comment '姓名',
  4. age int comment '年龄',
  5. balance decimal(18, 2) comment '余额'
  6. )engine=myisam default charset=utf8;
  7. insert into bank_myisam(name, age, balance) values('zhangsan', 22, 1000);
  8. insert into bank_myisam(name, age, balance) values('lisi', 18, 2000);
  9. insert into bank_myisam(name, age, balance) values('wangwu', 20, 3000);
  10. insert into bank_myisam(name, age, balance) values('zhaoliu', 21, 4000);
  11. insert into bank_myisam(name, age, balance) values('tom', 19, 5000);
  12. insert into bank_myisam(name, age, balance) values('jack', 24, 6000);
  13. insert into bank_myisam(name, age, balance) values('lilei', 22, 7000);
  14. insert into bank_myisam(name, age, balance) values('lily', 18, 8000);

5、 演示MyISAM表锁

# myisam的表锁

# bank_myisam表加读锁
lock tables bank_myisam read;

select * from bank_myisam;

unlock tables;
# myisam的表锁

select * from bank_myisam;

update bank_myisam set balance = balance + 100 where id = 1;

6 、演示InnoDB行锁

# 事务A
# InnoDB的行锁
# insert、update、delete自动加锁
begin;

select * from bank_innodb;

# 手动加写锁
select * from bank_innodb where id = 2 for update;

commit;
# 事务B
# InnoDB的行锁

begin;

select * from bank_innodb;

update bank_innodb set balance = balance + 200 where id = 2;

commit;