MySQL的锁


1、MySQL的锁的基本介绍

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

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

1.1、数据库锁的分类

从对数据操作的类型:

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

从对数据操作的粒度分:

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
  • 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  • 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般

2.1、表锁的相关SQL操作

2.1、查看哪些表被锁定

可以通过以下命令来查看哪些表被锁定:

show open tables;

结果示例如下:

结果说明如下:

  • Database:含有该表的数据库
  • Table:表名称
  • In_use:表当前被查询使用的次数。如果该数为零,则表是打开的,即当前没有锁表。如果某个表被锁表,则该表的 In_use 字段不会是 0
  • Name_locked:表名称是否被锁定。名称锁定用于取消表或对表进行重命名等操作

2.2、给表加锁

可以使用以下命令给表加锁:

lock table 表名 read(write), 表名2 read(write), 其他;

-- 示例
lock table lock_table_test read, lock_table_test2 write;

示例:

先创建一个表 mylock:

create table mylock (
    id int not null primary key auto_increment,
    name varchar(20) default ''
) engine myisam;

insert into mylock(name) values('a');
insert into mylock(name) values('b');
insert into mylock(name) values('c');
insert into mylock(name) values('d');
insert into mylock(name) values('e');

然后给该表加读锁:

lock table mylock read;

使用 show open tables; 来查看表锁情况:

可以看到,mydbtest.mylock 表已被锁定。

2.3、释放表锁

释放所有表的锁:

unlock tables;

3、表级锁(读写锁)

3.1、读锁

假设一个会话 A 对 mylock 表进行了读锁,则:

  • A 会话可以查该表的数据,但是无法增删改该表的数据,并且也无法查询其他表的数据,即使其他表未被锁定也无法查询,直到对该锁表进行释放锁。
  • 其他的会话比如新起了一个会话B,可以查询该锁表的数据,也可以查询、增删改其他表的数据。但是在对该已锁的数据进行增删改时,会一直阻塞,导致SQL无法执行结束,直到该表锁被释放后,SQL会自动执行结束。

也就是加锁的会话可以查锁表数据,但无法增删改,也无法查询其他表。新建的会话可以查询任何表的数据,但对锁表进行增删改时会阻塞,直到锁表的锁被释放。