mysql锁机制总结,以及优化建议
一、锁概述和分类

二、表锁
偏向MyISAM存储引擎,开销小,加锁快;无死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
【手动增加表锁】
lock table 表名字1 read(write),表名字2 read(write),其它;
【查看表上加过的锁】
show open tables;
【释放表锁】
unlock tables;
演示:
mysql> select * from mylock;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
| 5 | e |
+----+------+
5 rows in set (0.00 sec) # 给mylock表加读锁,给t1表加写锁
mysql> lock table mylock read, t1 write;
Query OK, 0 rows affected (0.02 sec) # 查看已经加锁的表, 下面的结果省略了很多行
mysql> show open tables;
+--------------------+------------------------------------------------------+--------+-------------+
| Database | Table | In_use | Name_locked |
+--------------------+------------------------------------------------------+--------+-------------+
| mysqlad | t1 | 1 | 0 |
| performance_schema | events_transactions_current | 0 | 0 |
| performance_schema | events_statements_summary_by_program | 0 | 0 |
| performance_schema | events_waits_summary_by_host_by_event_name | 0 | 0 |
| mysqlad | mylock | 1 | 0 |
| performance_schema | file_sum
121 rows in set (0.00 sec) # 释放表锁
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
读锁案例:下面通过两个会话窗口来演示对mylock表加读锁之后的效果:
| session_1 | session_2 |
|---|---|
获得表mylock的READ锁定![]() |
连接终端 |
当前session_1可以查询该表记录![]() |
其他session(session_2)也可以查询该表![]() |
当前session_1不能查询其它没有锁定的表。![]() |
其他session_2可以查询或者更新未锁定的表![]() |
当前session_1中插入或者更新锁定的表都会提示错误:![]() |
其他session_2插入或者更新锁定表会一直等待获得锁:(阻塞)![]() |
| 释放锁。 mysql> unlock tables; |
session_2立即释放阻塞,马上获得锁。![]() |
演示对mylock加写锁:
| seession_1 | session_2 |
|---|---|
获得表mylock的WRITE锁定, 当前session对锁定表的查询+更新+插入操作都可以执行:![]() |
其他session对锁定表的查询被阻塞, 需要等待锁被释放: ![]() 在锁表前,如果session2有数据缓存, |
| 释放锁 mysql> unlock tables; |
session_2立即被释放得到锁![]() |
通过上面的实验,可以发现:
MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行增删改操作前,会自动给涉及的表加写锁。
MySQL的表级锁有两种模式:
- 表共享读锁(Table Read Lock)
- 表独占写锁(Table Write Lock)
| 锁类型 | 他人可读 | 他人可写 |
|---|---|---|
| 读锁 | 是 | 否 |
| 写锁 | 否 | 否 |
结合上表,所以对MyISAM表进行操作,会有以下情况:
- 1、对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。
- 2、对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。
简而言之,就是读锁会阻塞写,但是不会堵塞读。而写锁则会把读和写都堵塞。
总结:
- 可以通过
show open tables来查看哪些表被枷锁了; - 如何分析表锁定,可以通过检查
table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定;

这里有两个状态变手记录MySQL内部表级锁定的情况,两个变量说明如下:
Table_locks_immediate: 产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1 ;
Table_locks_waited: 出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,每等待一次锁值加1),此值高则说明存在着较严重的表级锁争用情况;
总结: MyISAM的读写锁调度是写优先,这也是MyISAM不适合做写为主表的引擎。 因为写锁后,其他线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。
三、行锁
特点:
- 偏向InnoDB存储引擎,开销大,加锁慢;
- 会出现死锁;
- 锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级锁。
Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一些,但是在整体并发处理能力方面要远远优于MyISAM的表级锁定的。当系统并发量较高的时候,Innodb的整体性能和MyISAM相比就会有比较明显的优势了。
但是,Innodb的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让Innodb的整体性能表现不仅不能比MyISAM高,甚至可能会更差。
演示案例,建表SQL:
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); # 查询结果
mysql> select * from test_innodb_lock;
+------+------+
| a | b |
+------+------+
| 1 | b2 |
| 3 | 3 |
| 4 | 4000 |
| 5 | 5000 |
| 6 | 6000 |
| 7 | 7000 |
| 8 | 8000 |
| 9 | 9000 |
| 1 | b1 |
+------+------+
9 rows in set (0.00 sec)
测试: 读己之所写。

然后看session_1和session_2同时更新a = 4的情况:
更新但是不提交,即没有commit![]() |
session_2被阻塞,只能等待
![]() |
|---|---|
提交更新mysql> commit; |
解除阻塞![]() |
但是如果两个会话不是更新同一行呢?
如果不是更新同一行,则就算在session_1没有commit的时候,session_2也不会阻塞。

尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁。
举个例子: 因为我们的b是varchar类型的,更新的时候我故意将b的单引号去掉,此时MYSQL底层自动类型转换,但是此时就会导致索引失效,然后我们看下面,就会导致我们的行锁变成了表锁,从而导致阻塞等待。

间隙锁带来的插入问题:

【什么是间隙锁】
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,
InnoDB也会对这个“间隙”加锁(不放过一个),这种锁机制就是所谓的间隙锁(GAP Lock)。
【危害】
因为Query执行过程中通过过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。
间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。
面试题:常考如何锁定一行。
使用
for update。
【如何分析行锁定】
通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况
mysql>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:系统启动后到现在总共等待的次数;
对于这5个状态变量,比较重要的主要是
Innodb_row_lock_time_avg(等待平均时长),
Innodb_row_lock_waits(等待总次数)
Innodb_row_lock_time(等待总时长)这三项。
尤其是当等待次数很高,而且每次等待时长也不小的时候,我们就需要分析系统中为什么会有如此多的等待,然后根据分析结果着手指定优化计划。
最后可以通过SELECT * FROM information_schema.INNODB_TRX\G;来查询正在被锁阻塞的sql语句。
四、优化建议
- 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁;
- 尽可能较少检索条件,避免间隙锁;
- 尽量控制事务大小,减少锁定资源量和时间长度;
- 锁住某行后,尽量不要去调别的行或表,赶紧处理被锁住的行然后释放掉锁;
- 涉及相同表的事务,对于调用表的顺序尽量保持一致;
- 在业务环境允许的情况下,尽可能低级别事务隔离;
免费Java高级资料需要自己领取,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并发分布式等教程,一共30G。
传送门:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q
mysql锁机制总结,以及优化建议的更多相关文章
- mysql锁机制(转载)
锁是计算机协调多个进程或线程并发访问某一资源的机制 .在数据库中,除传统的 计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所 ...
- 再谈mysql锁机制及原理—锁的诠释
加锁是实现数据库并发控制的一个非常重要的技术.当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁.加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更 ...
- Mysql锁机制介绍
Mysql锁机制介绍 一.概况MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制.比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking ...
- mysql锁机制详解
前言 大概几个月之前项目中用到事务,需要保证数据的强一致性,期间也用到了mysql的锁,但当时对mysql的锁机制只是管中窥豹,所以本文打算总结一下mysql的锁机制. 本文主要论述关于mysql锁机 ...
- mysql锁机制 读书笔记
目录 MySQL锁机制 1.什么是锁 2.lock与latch 3.InnoDB存储引擎中的锁 3.1锁的类型 3.2 一致性非锁定读 3.3 一致性锁定读 4 锁的算法 4.1行锁的3中算法 4.2 ...
- Mysql锁机制--索引失效导致行锁变表锁
Mysql 系列文章主页 =============== Tips:在阅读本文前,最好先阅读 这篇(Mysql锁机制--行锁)文章~ 在上篇文章中,我们看到InnoDB默认的行锁可以使得操作不同行时不 ...
- 对mysql锁机制的学习
1.对于mysql学习,经常翻看一些博客,论坛,好像或多或少有mysq锁机制的学习与总结,所以今天有必要 对mysql锁机制的一些个人的总结,以便以后深入的学习. 2.学习这件事,从来都是“深入浅出” ...
- mysql锁机制和事务隔离
mysql事务 1.InnoDB事务原理 事务(Transaction)是数据库区别于文件系统的重要特性之一,事务会把数据库从一种一致性状态转换为另一种一致性状态. 在数据库提交时,可以确保要么所有修 ...
- (三)MySQL锁机制 + 事务
转: (三)MySQL锁机制 + 事务 表锁(偏读) 偏向MyISAM存储引擎.开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发最低. 查看当前数据库中表的上锁情况,0表示未上锁. sh ...
随机推荐
- ios webview
//#pragma mark - UIWebView Delegate Methods -(void)webViewDidFinishLoad:(UIWebView *)webView{ //获取到w ...
- 学习CNN系列二:训练过程
卷积神经网络在本质上是一种输入到输出的映射,它能够学习大量的输入与输出之间的映射关系,而不需要任何输入和输出之间精确的数学表达式,只要用已知的模式对卷积神经网络加以训练,网络就具有输入.输出之间映射的 ...
- React 受控组件和非受控组件
需求用户名自动获取 onChange用户状态发生改变 就获取值 就是时时获取值 使用onChange 点击按钮 获取密码 只要绑定了点击事件 就可以获取值 通过 let usercont=event. ...
- 201871010108-高文利《面向对象程序设计(java)》第十二周学习总结
项目 内容 这个作业属于哪个课程 <任课教师博客主页链接> https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 <作业链接地址> ht ...
- python27期day12:推导式、内置函数、高阶函数、匿名函数、作业题
1.推导式:做一些有规律的数据结构 列表推导式: 普通循环模式: [加工后的变量 for 循环] 示例一:print([i for i in range(1,51)]) 结果:[1, 2, 3, 4, ...
- node端console.log输出不同颜色文字
我们知道console.log直接输出是按着终端的默认颜色来显示的, console.log('message') 那么如何指定他们的颜色显示呢?很简单,直接再加一个参数就可以了,例如: consol ...
- zz在自动驾驶研发中充分发挥数据的潜能
本次分享内容提纲 数据标注 数据驱动开发 数据驱动决策 前言 上图这是我加入小马智行之前的一个小故事.这不断的提醒我,人工智能需要有足够的数据量,并且充分发挥这些数据的潜能,是我们作为人工智能公司的一 ...
- CF1193A Amusement Park
洛谷 CF1193A Amusement Park 洛谷传送门 题目翻译 有一个游乐场有一个好玩的项目:一些有向滑梯可以将游客从一个景点快速.刺激地传送到另一个景点.现在,你要帮游乐场老板来规划一个造 ...
- 洛谷 U86564 排队形
洛谷 U86564 排队形 题目传送门 题目背景 \(JDFZ2019\)秋季运动会开始辣!为了使强大的高一 · \(6\)班有一个更好的精神面貌,班主任\(T\)老师和体委\(LY\),\(LYB\ ...
- 6-ESP8266 SDK开发基础入门篇--操作系统入门使用
了解了8266的串口了,这一节咱就自己写程序,处理一下数据,如果接收到 0xaa 0x55 0x01 就控制指示灯亮 0xaa 0x55 0x00 就控制指示灯灭 注意哈,我是用的假设没有操作系统 ...














