MySQL性能优化(八)-- 锁机制之表锁

数据库的锁主要用来保证数据的一致性的。MyISAM存储引擎只支持表锁,InnoDB存储引擎既支持行锁,也支持表锁,但默认状况下是采用行锁。mysql

1、锁分类

1.按照对数据操做的类型分:读锁,写锁sql

  • 读锁:也称为共享锁。 针对同一资源,多个并发读操做能够并行执行,而且互不影响,可是不能写
  • 写锁:也称排它锁。当前线程写数据的时候,会阻塞其它线程来读取数据 或者 写数据

注:读锁和写锁都是阻塞锁。数据库

2.按照数据操做的粒度:表锁,行锁,页锁bash

  • 表锁:开销小,加锁快,主要在myisam存储引擎中出现。特色:锁住整个表,开销小,加锁快,无死锁状况, 锁的粒度大,在并发状况下,产生锁等待的几率比较高,因此说,支持的并发数比较低,通常用于查找
  • 行锁:开销大,加锁慢,锁定单独的某个表中的某一行记录,主要用于innodb存储引擎。特色:有死锁状况,锁定粒度最小,发生锁冲突的几率最低,支持的并发数也最高
  • 页锁:开销和加锁时间界于表锁和行锁之间。会出现死锁,锁定粒度界于表锁和行锁之间,并发度通常

2、加锁与解锁

1.手动增长表锁并发

lock table 表名 [read|write],表名 [read|write]…优化

2.解锁ui

unlock tables;spa

3.查看哪些表被锁线程

show open tables;3d

3、表锁案例

1.读锁

create table lock_one(
     id int primary key auto_increment,
     col int
)engine=myisam;

insert into lock_one(col) values (1);
insert into lock_one(col) values (2);
insert into lock_one(col) values (3);
复制代码

下面咱们模拟两个用户,即两个线程链接数据库,开启两个xsheel窗口,链接到mysql:

  1. 在会话1中对lock_one表增长读锁
lock table lock_one read;
复制代码
  1. 在当前会话(会话1)中是否能够select该表呢,也就是说对 lock_one增长了读锁后,在当前会话中是否能够读呢?
select * from lock_one;
复制代码

答案是能够的。

  1. 在另外一个会话中(会话2)是否能够select该表呢?

答案也是能够的。

  1. 那么在会话1中是否能够查询其余表呢?

例如,查询 users表:select * from users;

img

咱们发现是不能够查询其余表的,这是由于当前会话已经对lock_one表加上了锁,即当前线程锁住了lock_one表,只能够操做lock_one表,就不能够查询其余的表。

  1. 问题来了,会话2是否能够查询其余表呢?
select * from users;
复制代码

img
   咱们发现是能够的。由于会话2和会话1是没有关系的,会话2查询会话1锁住的表均可以,查询没有锁住的 确定是能够的。

  1. 在会话1中是否能够更新(增删改)锁住的lock_one表呢?
update lock_one set col=66 where id=1;
复制代码

img

发现是不能够的,由于咱们对 lock_one表加了 读锁,因此是不能够 进行写操做的。

  1. 在会话2中是否能够更新(增删改)会话1中锁住的lock_one表呢?

img

咱们发现是没有执行结果的,也就是说 正在等待更新,在阻塞等待中。由于咱们在会话1中对lock_one中增长了读锁,其余人只有读的操做,没有写的操做。

  1. 在会话1中 对lock_one进行解锁时,会话2中的更新(增删改)操做 就会当即执行。

img

2.写锁

  1. 在会话1中对lock_one表增长写锁
lock table lock_one write;
复制代码
  1. 在会话1中查询该表
select * from lock_one;
复制代码

咱们发现是能够的。

  1. 在会话2中查询该表

img

咱们发现是没有执行结果的,也就是说 处于阻塞状态。由于写锁是排它锁,其余用户线程不能够读取当前锁住的表,只有解锁以后 其余用户线程才能够执行select

img

  1. 在会话1中对lock_one进行写锁后,会话1会否能够查询其余表呢?
select * from users;
复制代码

img

咱们发现是不能够的。道理和读锁的时候同样,当前会话已经对lock_one表加上了锁,即当前线程锁住了lock_one表,只能够操做lock_one表,就不能够查询其余的表。

  1. 那么在会话2中是否能够查询其余表呢?

答案确定是能够的。由于之和锁的表有关系,和其余表没有任何关系。

  1. 在会话1中是否能够进行写(增删改)操做呢?

答案必定是能够的。由于会话1对lock_one表进行了写锁操做,也就是只能够写。

  1. 在会话2中是否能够进行写(增删改)操做呢?

img

咱们发现是不能够的。由于写锁是排它锁,也就是只能够当前线程操做锁住的表,其余用户线程须要等到解锁以后才能够操做该表。

img

3.总结

  1. 甲对表A加了读锁
  • 甲对表A能够执行读(查询)操做,但不能够执行写(增删改)操做
  • 甲对其余表不能够执行读写(增删改查)操做
  • 乙对表A能够执行读(查询)操做,但不能够执行写(增删改)操做
  • 乙对其余表能够执行读写(增删改查)操做

img

  1. 甲对表A加了写锁
  • 甲对表A能够执行读写(增删改查)操做
  • 甲对其余表不能够执行读写(增删改查)操做
  • 乙对表A不能够执行读写(增删改查)操做
  • 乙对其余表能够执行读写(增删改查)操做

img

4、MyISAM存储引擎中锁特色

  • 执行select语句的时候,会自动给涉及的表加上表锁,在执行更新操做时,会自动给表加上写锁
  • MyISAM存储引擎比较适合做为以查询为主的表存储引擎,不适合写为主的表存储引擎,由于加写锁后,是锁住整个表,其余用户线程不能作任何操做,这样会致使大量用户线程阻塞的状况。

5、表锁的状态查询

1.查询指令

show status like 'table_lock%';

img

说明:

  • Table_locks_immediate:表示能够当即获取锁的查询次数,每获取一次锁就增长1
  • Table_locks_waited:锁等待的次数(重要,若是这个值的大,则说明锁表的次数多,须要优化,经过 show open tables,查看哪些表锁了,而后分析为何会锁)。

欢迎关注个人公众号,第一时间接收最新文章~ 搜索公众号: 码咖 或者 扫描下方二维码:

img
相关文章
相关标签/搜索