20.Mysql锁机制

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

20.1 Mysql锁概述
锁类型分为表级锁、页面锁、行级锁。
表级锁:一个线程对表进行DML时会锁住整张表,其它线程只能读该表,如果要写该表时将产生锁等待。
优点:开销少、加锁快、不会产生死锁。缺点:锁粒度大、容易产生锁等待、并发低。
行级锁:一个线程对表进行DML时会锁住该表影响的行,其它线程可以读该表,也可以DML该表其它的行,如果要DML已被锁定的行时将产生锁等待。
缺点:开销大、加锁慢、会产生死锁。优点:锁粒度小、不容易产生锁等待、并发高。
页面锁:一个线程对表进行DML时会锁住该表影响行的所在页面(dbblock),其它线程可以读该表,也可以DML该表其它的页面(dbblock),如果要DML已被锁定的页面(dbblock)时将产生锁等待。
页面锁介于表级锁和行级锁中间,会产生死锁,并发一般,表只有一个页面(dbblock)时等同于表级锁。
Mysql不同的存储引擎支持不同的锁机制。
MyISAM和MEMORY存储引擎支持表级锁;
BDB存储引擎支持页面锁;
INNODB存储引擎支持行级锁。

20.2 MyISAM表锁
20.2.1 查询表级锁争用情况
状态变量table_locks_immediate:立即加锁的次数
状态变量table_locks_waited:产生锁等待的次数

20.2.2 Mysql表级锁的锁模式
共享读锁lock table 表名 read:一个进程的读操作,不阻断其它进程的读操作,但阻断其它进程的写操作。
独占写锁lock table 表名 write:一个进程的写操作,阻断其它进程的读操作和写操作。
读操作之间的并行的,读写操作之间是串行的,写操作之间是串行的。
释放锁unlock tables:释放所有锁。

20.2.3 如何加表锁
select 语句会自动给涉及的表加读锁;
insert\update\delete 语句会自动给涉及的表加写锁;
也可通过命令 lock table 表名 read/write 显示的加读/写锁。
lock table 表名 read local; --增加local选项指读操作只锁定表中现有记录,其它进程可以增加新的记录,但不能删除、修改现有记录。
读写操作加锁时会给涉及的所有表加锁,如果其中哪个表已经被其它进程锁定(且非共享读锁)时,将产生锁等待。
Mysql不支持锁升级,使用lock table 表名 read加锁后,进程只能访问被自己加锁的表(不能访问未加锁的表),且必须按已加锁的锁模式来访问(加的读锁时不能进行写操作)。
使用lock table 表名 read加锁后,不能对表起别名。

20.2.4 并发插入(Concurrent Inserts)
系统变量concurrent_insert=[0|1|2] 控制并发插入行为。指表被读锁锁定时,是否允许其它进程在表的末尾进行插入数据。
0 不允许并发插入;1 表没有空洞(中间被删除的行)时允许在表尾进行并发插入;2 允许在表尾进行并发插入。
optimize table命令可以整理空间碎片,回收因删除操作产生的空洞。

20.2.5 MyISAM的锁调度
MyISAM的锁调度策略:读写互斥,读写串行,写锁优先。
问题1:存在大量DML操作时,DQL操作很难获得读锁,长时间被阻塞。
启动参数low-priority-updates,系统层面降低写请求优先级
set low-priority-updates=1 会话层面降低写请求优先级
在insert/update/delete语句后增加low-priority属性 语句层面降低写请求优先级
系统参数max_write_lock_count=x, 当一个表的读锁达到阈值x时,Mysql暂时降低写请求优先级,给读进程一个获得锁的机会。
问题2:耗时长的读进程,也会导致写进程所等待并超时。
应尽量避免耗时长的查询,通过SQL优化或将复杂SQL拆分为多条SQL语句。

20.3 InnoDB锁问题
InnoDB支持事务采用了行级锁。
20.3.1 背景知识
1.事务及其ACID属性
事务是一组SQL语句组成的逻辑处理单元,事务具有原子性(Atomicity)、一致性(Consistent)、隔离性(Isolation)、持久性(Durable)4个特性。
原子性:事务中的一组SQL要么全部执行,要么全部回退,不能部分执行。
一致性:事务开始和完成时数据必须保持一致状态。
隔离性:事务在一个session中运行,不受其它session影响,事务的中间状态对外不可见。
持久性:事务完成后数据的修改是永久性的。

2.并发事务处理带来的问题
更新丢失:多个事务基于同一行的更新操作可能相互覆盖。通过锁机制消除。
脏读:一个事务修改了数据,尚未提交完成时,另一个事务读取了修改后的数据,称为脏读。通过快照提供读一致性。
不可重复读:一个事务中两次读取同一个数据,读取结果不同时,称为不可重复读。
幻读:一个事务中两次读取同一个数据,读取结果数量不同时,称为幻读。

3.事务的隔离级别
脏读、不可重复读、幻读都是读一致性问题,可以通过事务的隔离机制里解决。
数据库实现事务隔离的方式分为:锁和快照。
锁方式事务隔离:在读取数据前对其加锁,防止其它事务对数据进行修改。
快照方式事务隔离:生成一个数据请求时间点的一致性数据快照,使用快照来提供一定级别的读一致性。
隔离性越严格,并发的问题越少,并发量越低。事务隔离实质就是将并发事务串行化执行。
ISO SQL92定义了4个事务隔离级别:
读未提交Read uncommitted:存在脏读、不可重复读、幻读
读已提交Read committed :不存在脏读,存在不可重复读、幻读
可重复读Repeatable read :不存在脏读、不可重复读,存在幻读
可序列化Serializable :不存在脏读、不可重复读、幻读
Mysql提供参数tx_isolation设置事务隔离级别,默认为可重复读Repeatable-read。

20.3.2 获取InnoDB行锁争用情况
状态变量:
InnoDB_row_lock_waits 锁等待次数
InnoDB_row_lock_time 锁等待时间
InnoDB_row_lock_time_avg 锁等待平均时间
InnoDB_row_lock_time_max 锁等待单次最大时间
InnoDB_row_lock_current_waits 当前的锁等待次数
如果锁等待次数和锁等待平均时间的值比较高,说明系统存在严重的锁争用。
可以通过information_schema模式下的innodb_locks和innodb_lock_waits表查看。
也可以创建innodb_monitor表监控发生锁冲突的表和数据行:
create table innodb_monitor(a int)engine=innodb;
打开监控后通过show engine innodb status;命令,会输出详细的锁等待信息,包括:表名、锁类型、锁定的记录等。
打开监控后15秒后系统向.err文件记录监控内容,.err文件会急剧增加,确定问题后需要停止监控,即删除innodb_monitor表。
停止监控时需要drop table innodb_monitor;

20.3.3 InnoDB的行锁模式及加锁方法
InnoDB的行锁模式分为共享锁、排他锁、意向共享锁、意向排他锁。
共享锁(S): 允许一个事务读一行,阻止其它事务写这一行
排他锁(X): 允许一个事务写一行,阻止其它事务读这一行或写这一行
意向共享表锁(IS): 事务在加S锁之前,应先取得表的IS锁
意向排他表锁(IX): 事务在加X锁之前,应先取得表的IX锁
锁兼容:如果一个事务请求的锁模式与当前的锁模式兼容,InnoDB就将请求的锁授予该事务。
锁等待:如果一个事务请求的锁模式与当前的锁模式不兼容,InnoDB就将该请求挂起,等待当前的锁释放,产生锁等待。
IS S IX X
IS ok ok ok no
S ok ok no no
IX ok no ok no
X no no no no
意向锁是InnoDB自动添加的,不需要用户干预。
insert/update/delete/select ... for update 会自动添加X锁。
select 不会添加任何锁。
手动加S锁方法:select * from 表名 where ... lock in share mode;
手动加X锁方法:select * from 表名 where ... for update;

20.3.4 InnoDB行锁实现方式
InnoDB行锁是给索引上的索引项加锁实现的。
如果没有索引,InnoDB将通过隐藏的聚簇索引来对记录加锁。
Record lock:对索引项加锁
Gap lock:对索引项之间的间隙(包括:第一条记录前的间隙和最后一条记录后的间隙)加锁。
Next-key lock:对记录及其前面的间隙加锁。
在不通过索引条件检索数据时,则对表中所有记录加锁。
select * from emp where empno=7788 for update; --empno列有索引,所以只对emp表中7788一行加锁
select * from emp where ename=‘scott‘ for update; --ename列没有索引,所以对emp表中所有记录加锁
对唯一索引的某个键值加锁时只锁定一行,对非唯一索引的某个键值加锁时将锁定这个键值对应的多行记录。
当表中有多个索引时,不同的事务可以使用不同索引锁定不同的行,但不能是同一行。无论使用的索引的类型。
即便在SQL的where条件中使用了索引列,但是否使用索引由Mysql执行计划决定,如果索引失效将对表中全部记录加锁。

20.3.5 Next-Key锁
在使用范围条件并请求共享锁或排他锁时,InnoDB会给符合条件的已有记录的索引项加锁,
对于符合条件但并不存在的记录称为“间隙”,InnoDB会给间隙也加锁,这种机制称为Next-Key锁。
Next-Key锁的作用在于防止幻读,并满足Mysql恢复和复制的需要。
业务中应尽量使用等值条件,避免使用范围条件,以降低Next-Key锁等待。
在等值条件中请求给一个不存在的记录加锁,InnoDB也会使用Next-Key锁。

20.3.6 恢复和复制的需要,对InnoDB锁机制的影响
Mysql通过binlog记录执行成功的DML操作,并由此实现Mysql的数据库恢复和主从复制。
binlog日志格式分为:基于语句的日志格式SBL、基于行的日志格式RBL和混合格式。
Mysql 4中复制模式:基于SQL语句的复制SBR、基行数据的复制RBR、混合复制模式和使用全局事务ID(GTIDs)的复制。
基于SQL语句的复制SBR要求:一个事务未提交前,其它并发事务不能插入满足其锁定条件的任何记录,即不允许出现幻读。
即使在其它隔离级别下,InnoDB均会使用Next-Key锁保证复制的串行化。
对复制语句create table tab_name select ...和insert into table_name select ... Mysql为保证恢复和复制的正确性增加了共享锁。
系统参数innodb_locks_unsafe_for_binlog=[off|on] 默认未off。
当设置未on时,给复制语句不加锁,但有可能导致复制不一致。

20.3.7 InnoDB在不同隔离级别下的一致性读及锁的差异
锁和快照是Innodb实现一致性读和SQL92隔离级别的方法,
不同隔离级别下Innodb处理SQL时采用的一致性读策略和需要的锁是不同的。
读未提交 读已提交 可重复度 可序列化
select 相等 None locks None locks None locks None locks
select 范围 None locks None locks None locks S Next-Key
insert X X X X
update 相等 X X X X
update 范围 X Next-Key X Next-Key X Next-Key X Next-Key
delete 相等 X X X X
delete 范围 X Next-Key X Next-Key X Next-Key X Next-Key
replace 无键冲突 X X X X
replace 键冲突 X Next-Key X Next-Key X Next-Key X Next-Key
lock in S 相等 S S S S
lock in S 范围 S S S Next-Key S Next-Key
for update 相等 X X X X
for update 范围 X S(X) X Next-Key X Next-Key
复制数据 off S Next-Key S Next-Key S Next-Key S Next-Key
复制数据 on None locks None locks None locks S Next-Key
复制表 off S Next-Key S Next-Key S Next-Key S Next-Key
复制表 on None locks None locks None locks S Next-Key
说明:
lock in S 指 手动添加S锁 select * from 表名 where ... lock in share mode;
for update 指 手动添加X锁 select * from 表名 where ... for update;
复制数据 指 insert into 表名 select ...
复制表 指 create table 表名 select ...
on 指 系统参数innodb_locks_unsafe_for_binlog=on
off 指 系统参数innodb_locks_unsafe_for_binlog=off
None locks 指 没有加任何锁
S 指 Share lock 行级共享锁
X 指 Exclusive lock 行级排他锁
S Next-Key 指 Share Next-Key 行级共享间隙锁
X Next-Key 指 Exclusive Next-Key 行级排他间隙锁
相等 指 条件中使用主键列的等值比较,即只处理一条记录
范围 指 条件中使用主键列的范围比较或非主键列比较或未使用索引,即处理多条记录
注意:隔离级别越高,加锁越严格,锁冲突的可能性就越高,并发性越低。
设置隔离级别的方法:
1.修改my.cnf文件中tx_isolation系统参数
tx_isolation=READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE;
2.动态修改参数
set [session|gloabl] tx_isolation=READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE;
3.在程序中执行
set session transactionn isolation READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE;

20.3.8 什么时候使用表锁
事务和行锁是Innodb被选择的原因,个别特殊事务中可以考虑使用表级锁。
场景1:事务需要更新大部分或全部数据(大量数据)时,使用表级锁可以提升性能。
场景2:事务涉及多个表且逻辑复杂,很可能一起死锁而造成大量事务回滚时,使用表级锁可以避免死锁,减少回滚。
使用表级的方法:
set autocommit=0; -- 关闭自动提交功能,否则Mysql不会给表加锁
lock tables 表名1 write|read,...; -- 添加表级锁,可以一次给多个表添加
要处理的事务SQL
commit; -- 提交或回退事务,commit或rollback不能释放表级锁
unlock tables; -- 释放全部表级锁,unlock tables可以隐式提交事务
说明:
表锁不是InnoDB存储引擎管理的,而是由Mysql Server管理,
仅当autocommit=0(默认为1)、innodb_table_locks=1(默认为1)时,
InnoDB引擎才能感知Mysql server是否添加了表锁,Mysql server才能感知InnoDB引擎是否添加了行锁。
否则,InnoDB将无法自动检测和处理因Mysql server添加了表锁而与已有行锁的冲突以及死锁。

20.3.9 关于死锁
MyIASM引擎只有表级锁,且需要一次获取所有的锁,要么全部满足,要么等待,不会产生死锁。
InnoDB引擎是行级锁,锁是由事务中的单条SQL逐步获取的,所以可能会产生死锁。
死锁是指A\B两个事务各有一个排他锁,且需要获得对方已占有排他锁,才能结束自身的事务,此时产生的相互的锁等待称为死锁。
InnoDB可以自动检测死锁,并回退其中一个事务,释放该事务占有的锁,使另一个事务获取要请求的锁,继续完成该事务。
在涉及外部锁和表锁时,InnoDB并不能检测到死锁,而是通过锁等待超时参数innodb_lock_wait_timeout来释放等待超时的事务的锁来解决死锁问题。
大量事务的锁等待会占用大量计算机资源,引起性能问题,所以要设置合适的锁等待超时参数innodb_lock_wait_timeout阈值。
死锁一般都是应用设计的问题,可以通过调整业务流、数据库对象、事务大小、以及SQl语句来解决,从而从根本上避免死锁。
减少死锁方法:
1.程序并发存取多个表时,应尽量约定以相同的顺序来访问表。
2.在批量处理数据时,应对数据排序,以固定的顺序来处理记录。
3.在事务中应该直接申请足够级别的锁,避免逐步的锁升级。
4.将默认隔离级别由REPEATABLE READ降低至READ COMMITTED。
5.事务报错后应使用rollback语句释放已获得的排他锁。
6.可以通过show innodb status;命令分析最后一个死锁产生的原因,
包括:引发死锁的SQL语句,事务已获得的锁,正在等待的锁,以及被回滚的事务等。
依此分析死锁产生的原因和改进措施。

20.4 小结
减少锁等待和死锁次数的措施:
1.尽量使用较低的隔离级别;
2.精心设计索引,并尽量使用索引访问数据,使加锁更加准确,从而减少锁冲突的机会;
3.选择合理的事务大小,小事务发生锁冲突的几率更小;
4.给记录集显示加锁时,最好一次性请求足够级别的锁,而不是逐步进行锁升级;
5.不同程序访问一组表时,应尽量约定以相同的顺序访问各个表,对一个表而言,尽可能以固定的顺序存取表中的行;
6.尽量使用相等条件访问数据,避免Next-Key锁的影响;
7.不要申请超过实际需要的锁级别,除非必须,否则查询时不要显示加锁;
8.对特定事务,可以使用表锁来提高处理速度或减少发生死锁的几率。

原文地址:https://www.cnblogs.com/BradMiller/p/10123404.html

时间: 2024-10-11 20:00:00

20.Mysql锁机制的相关文章

mysql锁机制详解

前言 大概几个月之前项目中用到事务,需要保证数据的强一致性,期间也用到了mysql的锁,但当时对mysql的锁机制只是管中窥豹,所以本文打算总结一下mysql的锁机制. 本文主要论述关于mysql锁机制,mysql版本为5.7,引擎为innodb,由于实际中关于innodb锁相关的知识及加锁方式很多,所以没有那么多精力罗列所有场景下的加锁过程并加以分析,仅根据现在了解的知识,结合官方文档,说说自己的理解,如果发现有不对的地方,欢迎指正. 概述 总的来说,InnoDB共有七种类型的锁: 共享/排它

mysql锁机制(转载)

锁是计算机协调多个进程或线程并发访问某一资源的机制 .在数据库中,除传统的 计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数据库必须解决的一 个问题,锁冲突也是影响数据库并发访问性能的一个重要因素. 从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂.本章我们着重讨论MySQL锁机制 的特点,常见的锁问题,以及解决MySQL锁问题的一些方法或建议. MySQL锁概述相对其他数据库而言,MySQL的锁机制比较简单,

对mysql锁机制的学习

1.对于mysql学习,经常翻看一些博客,论坛,好像或多或少有mysq锁机制的学习与总结,所以今天有必要 对mysql锁机制的一些个人的总结,以便以后深入的学习. 2.学习这件事,从来都是“深入浅出”的,今天留个痕迹,说不定以后“受益匪浅”. a.数据库锁是什么 数据库锁就是为了保证数据库数据的一致性在一个共享资源被并发访问时使得数据访问顺序化的机制. MySQL数据库的锁机制比较独特,支持不同的存储引擎使用不同的锁机制. b.mysql锁机制的3中类型 表级锁,行级锁,页级锁 c.各级锁的特点

Mysql锁机制和事务控制

如何加锁 锁定表的语法:    LOCK TABLES    tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}    [, tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}] ...解锁语法:    UNLOCK TABLES innodb的存储引擎提供行级锁,支持共享锁和排他锁两种锁定模式,以及四种不同的隔离级别. 死锁 InnoDB自动检测事务的死锁,并回滚一个

mysql锁机制整理

Auth: jinDate: 20140506 主要参考整理资料MYSQL性能调优与架构设计-第七章 MYSQL锁定机制http://www.cnblogs.com/ggjucheng/archive/2012/11/14/2770445.html理解MySQL--架构与概念http://www.cnblogs.com/yequan/archive/2009/12/24/1631703.html 一.mysql锁类型及应用介绍1.锁类型和应用类型相對其他數據庫而言,MySQL的鎖機制比較簡單,其

Mysql 锁机制和事务

InnoDB 锁机制 InnoDB存储引擎支持行级锁 其大类可以细分为共享锁和排它锁两类 共享锁(S):允许拥有共享锁的事务读取该行数据.当一个事务拥有一行的共享锁时,另外的事务可以在同一行数据也获得共享锁,但另外的事务无法获得同一行数据上的排他锁 排它锁(X):允许拥有排它锁的事务修改或删除该行数据. 当一个事务拥有一行的排他锁时,另外的事务在此行数据上无法获得共享锁和排它锁,只能等待第一个事务的锁释放 除了共享锁和排他锁之外, InnoDB也支持意图锁.该锁类型是属于表级锁,表明事务在后期会

6.mysql 锁机制

概述 定义: 锁是计算机协调多个进程或者线程并发访问某一资源的机制 在数据库中,除传统的计算资源(如CPU,RAM,IO等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发 访问的一致性.有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素.从这个角度 来说,锁对数据库而言显得尤其重要,也更加复杂. 实际场景案例:生活购物 打个比方,我们在淘宝上抢购一件商品,商品只有一件库存,这个时候如果有很多人想去买,那么如何解决是你买到还是其他人买到的问题? 这

MySQL锁机制浅析

MySQL使用了3种锁机制 行级锁,开销大,加锁慢,会出现死锁,发生锁冲突的概率最高,并发度也最高 表级锁,开销小,加锁快,不会出现死锁,发生锁冲突的概率最低,并发度最低 页级锁,开销和加锁时间界于表锁和行锁之间:会出现死锁:锁定粒度界于表锁和行锁之间,并发度一般 MySQL的存储引擎,这里指常用的,InnoDB,默认是行级锁,如果不指定主键的话,那么就是表级锁了,这点切记 MyISAM是表锁 innoDB 先来了解下MySQL事务 事务是由一组sql语句组成的逻辑处理单元,有4个属性ACID

Mysql锁机制--乐观锁 & 悲观锁

前言 mysql的并发操作时而引起的数据的不一致性(数据冲突): 丢失更新:两个用户(或以上)对同一个数据对象操作引起的数据丢失. 解决方案:1.悲观锁,假设丢失更新一定存在:sql后面加上for update:这是数据库的一种机制. 2.乐观锁,假设丢失更新不一定发生.update时候存在版本,更新时候按版本号进行更新. 第一部分 悲观锁 1 概念 悲观锁,正如其名,它指的是对数据被外界(包括当前系统的其它事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于