写点什么

MySQL 锁机制

发布于: 2021 年 01 月 21 日
MySQL锁机制

一、概述

1,锁的定义

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

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

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

2,锁的分类

a)数据操作的类型

读锁 (共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响

写锁 (排它锁):当前写操作没有完成前,它会阻断其他写锁和读锁

b)数据操作的颗粒度

行锁

表锁

页锁

二、表锁

1,特点

偏向 MyISAM 存储引擎, 开销小加锁快,不会出现死锁锁定力度大 ,发生锁冲突概率高, 并发度最低

2,案例分析

#加锁方式lock table 表名1 read(write),表名2 read(write);#查看表上加过的锁 0表示未上锁show open tables;#释放锁unlock tables;
复制代码

a)建表

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');
select * from mylock;
复制代码

b)加读锁

在 session 1 中加锁

#给mylock表加读锁lock table mylock read;#查询mylock表  可以展示所有数据select * from mylock;#在当前会话中不能读取别的表:Table 'tbl_emp' was not locked with LOCK TABLESselect * from tbl_emp;
复制代码

在 session 2 中读取和修改

#可以查询select * from mylock;#修改mylock表会出先等待,直到mylock表释放锁update mylock set name='aaa' where id = 1;
复制代码

结论:当前 session 为当前表 加写读锁

  1. 当前 session 只能读取当前表,不能更新当前表 。并且不能操作其他表的读和写

  2. 其他 session 只能读取当前表,不能更新当前表(阻塞) 。可以操作其他表的读和写。

c)加写锁

在 session 1 中添加写锁

#给mylock表加写锁lock table mylock write;#查询mylock表  可以展示所有数据select * from mylock;#在当前会话中不能读取别的表:Table 'tbl_emp' was not locked with LOCK TABLESselect * from tbl_emp;
复制代码

在 session 2 中读取和更新

#在session 2中无法读取数据和更新数据,一直阻塞;直到session中unlock tables解锁select * from mylock;
复制代码

结论:当前 session 为当前表加写锁

  1. 当前 session 只能操作当前表的读和写 ,不能操作其他表的读和写

  2. 其他 session 不能操作当前表的读和写(阻塞) ,可以操作其他表。

d)总结

MyIsam 在执行查询语句( SELECT )前,会自动给涉及的 所有表加读锁 ,在执行增删改操作前 ,会自动给涉及的 表加写锁

对 MyISAM 表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。

对 MyISAM 表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。

简而言之,就是 读锁会阻塞写,但是不会堵塞读。而写锁则会把读和写都堵塞 。

三、行锁

1,特点

偏向 InnoDB 存储引擎, 开销大,加锁慢会出现死锁(间隙锁)锁定粒度最小 ,发生锁冲突的概率最低, 并发度也最高

InnoDB 与 MyISam 的最大不同有两个: 1.支持事务;2.采用行级锁。

2,事务

a)事务(Transation)及其 ACID

事务是由一组 SQL 语句组成的逻辑处理单元,事务具有以下 4 个属性,通常简称为事务的 ACID 属性。

  1. 原子性 (Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。

  2. 一致性 (Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如 B 树索引或双向链表)也都必须是正确的。

  3. 隔离性 (Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。

  4. 持久性 (Durability):事务院成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

b)事务隔离级别

MySQL 查看事务隔离级别:show variables like 'tx_isolation';

脏读: 事务 A 读取到了事务 B 已修改但 尚未提交的的数据 ,还在这个数据基础上做了操作。

不可重复读: 事务 A 读取到了事务 B 已经提交的修改数据,不符合隔离性

幻读: 第一个事务对一定范围的数据进行批量修改,第二个事务在这个范围内增加一条数据,这时候第一个事务就会 丢失对新新增数据的修改

3,行锁案例

a)创建表

CREATE TABLE test_innodb_lock (a INT(11),b VARCHAR(16))ENGINE=INNODB;
INSERT INTO test_innodb_lock VALUES(1,'b2');INSERT INTO test_innodb_lock VALUES(3,'3');INSERT INTO test_innodb_lock VALUES(4, '4000');INSERT INTO test_innodb_lock VALUES(5,'5000');INSERT INTO test_innodb_lock VALUES(6, '6000');INSERT INTO test_innodb_lock VALUES(7,'7000');INSERT INTO test_innodb_lock VALUES(8, '8000');INSERT INTO test_innodb_lock VALUES(9,'9000');INSERT INTO test_innodb_lock VALUES(1,'b1');
CREATE INDEX test_innodb_a_ind ON test_innodb_lock(a);CREATE INDEX test_innodb_lock_b_ind ON test_innodb_lock(b);
复制代码

b)操作同一行数据

操作同一行数据时:当上一个事务 修改未提交 时,第二个事务也去修改会 处于阻塞

c)操作不同行数据

操作不同行时:即使上一个事务修 改未提交 ,第二个事务也能修改, 互不影响

d)索引失效,表锁

修改 test_innodb_lock 中的数据, varchar 不用 ’ ’ ,导致系统自动转换类型,导致 索引失效,会出现 表锁

4,间隙锁

a)介绍

当我们用 范围条件 而不是相等条件检索数据,并请求 共享或排他锁 时,InnoDB 会给符合条件的已有数据记录的索引项加锁 ; 对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”

InnoDB 也会对这个“间隙”加锁,这种锁机制是所谓的间隙锁(Next-Key 锁)

b)示例

4,锁定某一行

select xxx ... for update 锁定某一行后,其它的操作会被阻塞,直到锁定行的会话提交 commit。

5,总结

Innodb 存储引擎由于实现了 行级 锁定,虽然在锁定机制的实现方面所带来的 性能损耗可能比表级锁定会要更高 一些,但是在整体 并发处理能力方面要远远优于 MyISAM 的表级锁定的。

当系统并发量较高的时候,Innodb 的整体性能和 MyISAM 相比就会有比较明显的优势了。

但是,Innodb 的行级锁定同样也有其脆弱的一面,当我们使用不当的时候( 索引失效,导致行锁变表锁 ),可能会让 Innodb 的整体性能表现不仅不能比 MyISAM 高,甚至可能会更差。

6,分析

show status like 'innodb_row_lock%'
复制代码


Innodb_row_lock_current_waits:当前正在等待锁定的数量;

Innodb_row_lock_time:从系统启动到现在 锁定总时间长度

Innodb_row_lock_time_avg: 每次等待所花平均时间

Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花的时间;

Innodb_row_lock_waits:系统启动后到现在 总共等待的次数

7,行锁优化

尽可能让所有数据检索都通过索引来完成, 避免无索引行锁升级为表锁

合理 设计索引,尽量缩小锁的范围

尽可能 减少检索条件 ,避免间隙锁

尽量控制事务大小,减少锁定资源量和时间长度

尽可能低级别事务隔离

四、页锁

开销和加锁时间界于表锁和行锁之间:会出现死锁;

锁定粒度界于表锁和行锁之间,并发度一般。

原文链接:http://www.cnblogs.com/bbgs-xc/p/14302996.html

如果觉得本文对你有帮助,可以关注一下我公众号,回复关键字【面试】即可得到一份 Java 核心知识点整理与一份面试大礼包!另有更多技术干货文章以及相关资料共享,大家一起学习进步!


发布于: 2021 年 01 月 21 日阅读数: 36
用户头像

领取资料添加小助理vx:bjmsb2020 2020.12.19 加入

Java领域;架构知识;面试心得;互联网行业最新资讯

评论 (1 条评论)

发布
用户头像
MySQL 锁机制
2021 年 01 月 21 日 15:44
回复
没有更多了
MySQL锁机制