一、锁的概述

在计算机中,锁是协调多个进程或线程并发访问某一资源的一种机制。

在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。

如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。

从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。

二、锁的分类

2.1 按数据操作的类型分类:

  • 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响。
  • 写锁(排它锁):当前操作没有完成之前,它会阻断其他的写操作或读操作。

2.2 按数据操作的粒度分:

  • 表锁:操作时,会锁定整个表。开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低。
  • 行锁:操作时,会锁定当前操作的表的某些行。开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高。
  • 页锁:操作时,会锁定当前操作的表的某些页。开销和加锁速度介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般。

很难笼统地说哪种锁更好,只能就具体应用的特点来说哪种锁更合适!

仅从锁的角度来说,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web 应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并查询的应用,如一些在线事务处理(OLTP)系统。

三、MySQL的锁

相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。InnoDB存储引擎支持行锁和表锁,MEMORY和MyISAM等存储引擎只支持表锁。

3.1 MyISAM的表锁

MyISAM存储引擎在执行查询语句(SELECT),会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等),会自动给涉及的表加写锁,这个过程并不需要用户干预。

为了方便演示,我们利用系统提供的显式加锁指令:

  • 读锁:lock table table_name read;
  • 写锁:lock table table_name write;
  • 解锁:unlock tables;

建立一个MyISAM存储引擎的表,并插入一些数据:

create table tb_myisam(
id INT AUTO_INCREMENT,
name VARCHAR(30),
age INT,
PRIMARY KEY(id)) engine=myisam;

insert into tb_myisam(name,age) value('zhang3',20);
insert into tb_myisam(name,age) value('li4',21);
insert into tb_myisam(name,age) value('wang5',22);

3.1.1 在两个会话终端来演示MyISAM的读锁:

3.1.2 演示MyISAM的写锁:

3.2 InnoDB的表锁和行锁

InnoDB存储引擎在执行更新操作(UPDATE、DELETE、INSERT等),会自动给涉及的表或行加写锁。InnoDB存储引擎对于普通SELECT语句,不会加任何锁。如果读的数据正在执行UPDATE或DELETE操作,这时读操作不会等待写锁的释放,而是直接读取该数据的快照,具体读取那份快照数据,和系统的隔离级别有关。对于SELECT语句,系统提供了显式加锁指令:

  • 读锁:select * from table_name where ... lock in share mode;
  • 写锁:select * from table_name where ... for update;

建立一个MyISAM存储引擎的表,并插入一些数据:

create table tb_innodb (
id INT AUTO_INCREMENT,
name VARCHAR(30),
age INT,
PRIMARY KEY(id)) engine=innodb;

insert into tb_innodb(name,age) value('zhang3',20);
insert into tb_innodb(name,age) value('li4',21);
insert into tb_innodb(name,age) value('wang5',22); 

为了方便演示,我们需要关闭系统的自动提交3.2.1 演示InnoDB表的读锁:

3.2.2 演示InnoDB表的写锁:

3.2.3 演示InnoDB行的读锁:

3.2.4 演示InnoDB行的写锁:

KunlunDB项目已开源

【GitHub:】
https://github.com/zettadb

【Gitee:】
https://gitee.com/zettadb

END

03-05 15:01