数据库锁设计的初衷是处理并发问题。作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则。而锁就是用来实现这些访问规则的重要数据结构。

根据加锁的范围,MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类。

全局锁

顾名思义,全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。

全局锁的典型使用场景是,做全库逻辑备份。也就是把整库每个表都 select 出来存成文本。

官方自带的逻辑备份工具是 mysqldump。当 mysqldump 使用参数–single-transaction 的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于 MVCC 的支持,这个过程中数据是可以正常更新的。

你一定在疑惑,有了这个功能,为什么还需要 FTWRL 呢?一致性读是好,但前提是引擎要支持这个隔离级别。比如,对于 MyISAM 这种不支持事务的引擎,如果备份过程中有更新,总是只能取到最新的数据,那么就破坏了备份的一致性。这时,我们就需要使用 FTWRL 命令了。

所以,single-transaction 方法只适用于所有的表使用事务引擎的库。如果有的表使用了不支持事务的引擎,那么备份就只能通过 FTWRL 方法。这往往是 DBA 要求业务开发人员使用 InnoDB 替代 MyISAM 的原因之一。

表级锁

MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。

表锁

表锁的语法是 lock tables … read/write。与 FTWRL 类似,可以用 unlock tables 主动释放锁,也可以在客户端断开的时候自动释放。需要注意,lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。

在还没有出现更细粒度的锁的时候,表锁是最常用的处理并发的方式。而对于 InnoDB 这种支持行锁的引擎,一般不使用 lock tables 命令来控制并发,毕竟锁住整个表的影响面还是太大。

元数据锁

MDL 不需要显式使用,在访问一个表的时候会被自动加上。MDL 的作用是,保证读写的正确性。你可以想象一下,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。

因此,在 MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。

读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。

读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。

需要注意的是:MDL 会直到事务提交才释放,在做表结构变更的时候,你一定要小心不要导致锁住线上查询和更新。

行锁

MySQL 的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如 MyISAM 引擎就不支持行锁。不支持行锁意味着并发控制只能使用表锁,对于这种引擎的表,同一张表上任何时刻只能有一个更新在执行,这就会影响到业务并发度。InnoDB 是支持行锁的,这也是 MyISAM 被 InnoDB 替代的重要原因之一。

在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。

知道了这个设定,对我们使用事务有什么帮助呢?那就是,如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

举个例子。

假设你负责实现一个电影票在线交易业务,顾客 A 要在影院 B 购买电影票。我们简化一点,这个业务需要涉及到以下操作:

从顾客 A 账户余额中扣除电影票价;

给影院 B 的账户余额增加这张电影票价;

记录一条交易日志。

也就是说,要完成这个交易,我们需要 update 两条记录,并 insert 一条记录。当然,为了保证交易的原子性,我们要把这三个操作放在一个事务中。那么,你会怎样安排这三个语句在事务中的顺序呢?

试想如果同时有另外一个顾客 C 要在影院 B 买票,那么这两个事务冲突的部分就是语句 2 了。因为它们要更新同一个影院账户的余额,需要修改同一行数据。

根据两阶段锁协议,不论你怎样安排语句顺序,所有的操作需要的行锁都是在事务提交的时候才释放的。所以,如果你把语句 2 安排在最后,比如按照 3、1、2 这样的顺序,那么影院账户余额这一行的锁时间就最少。这就最大程度地减少了事务之间的锁等待,提升了并发度。

死锁和死锁检测

当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。

这时候,事务 A 在等待事务 B 释放 id=2 的行锁,而事务 B 在等待事务 A 释放 id=1 的行锁。 事务 A 和事务 B 在互相等待对方的资源释放,就是进入了死锁状态。当出现死锁以后,有两种策略:

一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 来设置。

另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。

减少死锁的主要方向,就是控制访问相同资源的并发事务量。

mysql锁问题吗_Mysql锁的问题和解析相关推荐

  1. mysql表copy锁表吗_MySQL锁(二)表锁:为什么给小表加字段会导致整个库挂掉?...

    概述 表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持.最常使用的MYISAM与INNODB都支持表级锁定.表级锁定分为表共享 ...

  2. mysql锁简谈_mysql锁简谈

    1.mysql锁, 作用:解决因资源共享而造成的并发问题. 实例:买最好一件衣服X A: X 买: X加锁----->试衣服--下单--付款--打包-.------>X解锁 B: X 买: ...

  3. mysql 锁怎么使用_Mysql锁一般使用

    一些很小的项目一般不会特意使用或注意数据锁,其实在事务操作修改与删除时就已经有隐式加锁.一般所有涉及到共享数据都会考虑下数据的原始性问题,保证数据在使用或修改时原始性没有被破坏就需要锁定数据所有权:除 ...

  4. mysql 表锁的概念_MySQL 锁的一些简单概念

    1. 锁的粒度 在MySQL中,只要有多个请求需要在同一时刻修改数据,都会产生并发控制的问题.而锁的作用可以保证同一资源能被某个请求唯一使用. 加锁是会消耗系统资源的,包括获得锁.检查锁是否已解除.释 ...

  5. mysql 锁怎么使用_MySQL锁的用法之行级锁

    行级锁是MySQL中粒度最小的一种锁,他能大大减少数据库操作的冲突.但是粒度越小,实现的成本也越高.MYISAM引擎只支持表级锁,而INNODB引擎能够支持行级锁,下面的内容也是针对INNODB行级锁 ...

  6. mysql行锁怎么读_MySQL锁(三)行锁:幻读是什么?如何解决幻读?

    概述 前面两篇文章介绍了MySQL的全局锁和表级锁,今天就介绍一下MySQL的行锁. MySQL的行锁是各个引擎内部实现的,不是所有的引擎支持行锁,例如MyISAM就不支持行锁. 不支持行锁就意味着在 ...

  7. mysql 事物隔离界别_MySQL锁与事务隔离级别

    ------------恢复内容开始------------ 一.概述 1.锁的定义 锁是计算机协调多个进程或线程并发访问某一资源的机制. 在数据库中,除了传统的计算资源(如CPU.RAM.IO等)的 ...

  8. mysql行锁索引问题_Mysql锁机制--索引失效导致行锁变表锁

    =============== Tips:在阅读本文前,最好先阅读 这篇(Mysql锁机制--行锁)文章~ 在上篇文章中,我们看到InnoDB默认的行锁可以使得操作不同行时不会产生相互影响.不会阻塞, ...

  9. mysql 锁的类型_mysql锁的分类

    一. 按照对数据操作的粒度分为:表级锁.行级锁.页级锁.间隙锁 MyISAM和MEMORY采用表级锁(table-level locking) BDB采用页面锁(page-level locking) ...

  10. 小米id锁状态查询_MySQL锁机制与事务隔离级别

    01 什么是事务? 事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性. 原子性(Atomicity) :事务是一个原子操作单元,其对数据的修改,要么全都执行 ...

最新文章

  1. Java 多线程初探(二) - 通讯与协调
  2. 微信小程序验证车牌号(含新能源车牌)
  3. SAP Cloud for Customer里新的Lead UI对Mashup集成的支持原理
  4. 算法(7)-leetcode-explore-learn-数据结构-数组-小结
  5. ntpdate报错the NTP socket is in use, exiting
  6. c++播放音频( c++ play audio),为C++应用程序添加启动音效
  7. java 下载视频文件
  8. 知道焊缝长度如何确定节点板尺寸_钢结构节点板(钢结构节点板尺寸如何选取)...
  9. 预处理中的头文件stdio.h在哪?里面有什么?
  10. 北斗时间周和GPS时间周计算,JAVA为例
  11. Macbook Pro Air锁屏不进入睡眠
  12. 大数据概览以及当下实用的主流开发
  13. 如何用MATLAB预测未来人口,使用matlab对将来人口总数进行预测
  14. 使用Everything清理垃圾文件
  15. Operators(操作符)(创建、转换操作符)
  16. RFT 实用CODE
  17. uniapp获取云服务空间 数据
  18. FPGA的复位设计要醒目点啦
  19. 什么是 Daemon 线程
  20. Github 上的个人项目开源心得

热门文章

  1. HDU 3785 寻找大富翁
  2. .net4.0切换2.0时,SplitContainer”的对象强制转换为类型
  3. 深入浅出MVC框架模式
  4. 一个用户在同一时间只能登录一次
  5. 【Git/Github学习笔记】GitHub上README写法暨GFM语法解读
  6. ArcGIS栅格数据批量转换格式
  7. (bfs)广度优先 实现图的遍历
  8. pandas 入门(详看注释)
  9. python的标准库——turtle
  10. 基于Python的Landsat影像建设用地自动识别与提取