一、概述

为保证数据的一致性和完整性,需要对 事务间并发操作进行控制 ,因此产生了 锁冲突是影响数据库 并发访问性能 的一个重要因素。所以锁对数据库而言显得尤其重要,也更加复杂。

二、并发问题

  1. MySQL并发事务访问相同记录
    (1)读读情况
    允许这种情况的发生
    (2)写-写情况
    该图描述:当一个事务想对这条记录做改动时,首先会看看内存中有没有与这条记录关联的 锁结构 ,当没有的时候就会在内存中生成一个 锁结构 与之关联等其它事务再次访问该条记录时候,若已经有锁与之关联,那么就需要等待,自身的锁结构为true。
    (3)读写情况
    即一个事务进行读取操作,另一个进行改动操作。这种情况下可能发生 脏读不可重复读幻读 的问题。注意: MySQL在 REPEATABLE READ 隔离级别上就已经解决了 幻读 问题。
  2. 并发问题的解决方案
    (1)方案一:读操作利用多版本并发控制( MVCC ,下章讲解),写操作进行 加锁 。
    (2)方案二:读、写操作都采用 加锁 的方式。
    两个方案对比:
    (1)采用 MVCC 方式的话, 读-写 操作彼此并不冲突性能更高
    (2)采用 加锁 方式的话, 读-写 操作彼此需要 排队执行影响性能

三、锁的分类(不同角度)

从数据操作的类型划分:读锁、写锁

  1. 读锁 :也称为 共享锁 、英文用 S 表示。针对同一份数据多个事务的读操作可以同时进行而不会
    互相影响
    相互不阻塞的。
  2. 写锁 :也称为 排他锁 、英文用 X 表示。当前写操作没有完成前,它会阻断其他写锁和读锁。
    注意:对于 InnoDB 引擎来说,读锁和写锁可以加在表上也可以加在行上
    对读取的记录加X锁:SELECT … LOCK IN SHARE MODE; SELECT … FOR SHARE;
    对读取的记录加S锁:SELECT … FOR UPDATE;

从锁粒角度划分

表级别

  1. 表级别的 X锁、S锁:普通的读锁、写锁。注意InnoDB 存储引擎提供的表级 S锁 或者 X锁 是相当鸡肋,只会在一些特殊情况下,比方说崩溃恢复过程中用到
  2. 表级别的 意向锁:给更大一级别的空间(数据页或数据表)示意里面是否已经上过锁。注意:也就是说其实IS锁和IX锁是兼容的(IX、IX也兼容)并且它们也都与行级别的X锁、S锁兼容
  3. 表级别的 AUTO-INC锁
    InnoDB 存储引擎提供了个 innodb_autoinc_lock_mode 的系统变量。
    (1)当 innodb_autoinc_lock_mode = 0,就采用 AUTO-INC 锁,语句执行结束后才释放锁;
    (2)当 innodb_autoinc_lock_mode = 2,就采用轻量级锁,申请自增主键后就释放锁,并不需要等语句执行后才释放。
    (3)当 innodb_autoinc_lock_mode = 1:对于普通 insert 语句,自增锁在申请之后就马上释放;而对于 类似 insert … select 这样的批量插入数据的语句,自增锁还是要等语句结束后才被释放;

行级别

  1. 行级别的 记录锁
    普通的读锁(S)锁、写(X)锁。 对一行记录锁定

  2. 行级别的 间隙锁
    引出为了解决幻读问题而生
    概念锁定两条记录之间间隙(左开右开),使其中不能插入数据,也就防止了幻读问题产生
    注意如果对一条记录加了 gap锁 (不论是 共享gap锁 还是 独占gap锁 ),并不会限制其他事务对这条记录加 正经记录锁 或者继续加 gap锁这也说明了间隙锁只为解决防止插入幻影记录而生。
    特例给最后一条记录或者给Supremum加gap锁之后,可以阻止其他事务插入 number 值在 (20, +∞) 这个区间的新记录

  3. 行级别的 临键锁
    概念:一句话,记录锁与间隙锁的合体,左闭右开
    例如这个,在( 3,8 ] 这个区间中在锁还没有释放之前(拥有 gap锁 的该事务提交之前)不能插入记录。也就是,它既能保护该条记录,又能阻止别的事务
    将新记录插入被保护记录前边的 间隙 。

  4. 行级别的 插入意向锁(想要在间隙锁中保护的间隙中插入记录,等待时,会生成一个插入意向锁)
    概念:设计 InnoDB 的大叔规定事务在等待的时候也需要在内存中生成一个 锁结构 ,表明有事务想在某个 间隙 中插入新记录,但是现在在等待。
    注意插入意向锁并不会阻止别的事务继续获取该记录上任何类型的锁

页级别

  1. 页锁
    页锁的开销介于表锁和行锁之间,会出现死锁。锁定粒度介于表锁和行锁之间,并发度一般。
    每个层级的锁数量是有限制的,因为锁会占用内存空间, 锁空间的大小是有限的 。当某个层级的锁数量
    超过了这个层级的阈值时,就会进行 锁升级 。锁升级就是用更大粒度的锁替代多个更小粒度的锁,比如
    InnoDB 中行锁升级为表锁,这样做的好处是占用的锁空间降低了,但同时数据的并发度也下降了。

从锁的态度划分

悲观锁

概念对数据被其他事务的修改持保守态度,会通过数据库自身的锁机制来实现,从而保证数据操作的排它性每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据会 阻塞 直到它拿到锁

乐观锁

概念乐观锁认为同一数据的并发操作不会总发生,属于小概率事件不用每次都对数据上锁,但是在更新的时候判断一下在此期间别人有没有去更新这个数据不采用数据库自身的锁机制,而是通过程序来实现。
思路:一条记录,事务A读一次数据version是1然后进行修改判断version是否为1如果读的时候version是1,改的时候还是1,那么这就说明,在两次操作之间没有其它事务对该条记录操作。(以版本号机制为例子)
实现方式:
(1)乐观锁的版本号机制
(2)乐观锁的时间戳机制(原理相同

加锁方式

显示锁

通过特定的语句进行加锁,我们一般称之为显示加锁,例如:
(1)显示加共享锁: select … lock in share mode
(2)显示加排它锁: select … for update

隐式锁

概念一个事务对新插入的记录可以不显式的加锁(生成一个锁结构),但是由于事务id 这个牛逼的东东的存在相当于加了一个 隐式锁 。(必须加一个锁的原因,在一个事务中新插入的记录,并发的事务会对该记录进行读、或者写操作,这就造成了脏读、脏写)

事务id起的作用
(1)对于聚簇索引记录来说,有一个 trx_id 隐藏列,该隐藏列记录着最后改动该记录的 事务id 。那么如果在当前事务中新插入一条聚簇索引记录后,该记录的 trx_id 隐藏列代表的的就是当前事务的事务id ,如果其他事务此时想对该记录添加 S锁 或者 X锁 时,首先会看一下该记录的 trx_id 隐藏列代表的事务是否是当前的活跃事务如果是的话,那么就帮助当前事务创建一个 X锁 (也就是为当前事务创建一个锁结构, is_waiting 属性是 false ),然后自己进入等待状态(也就是为自己也创建一个锁结构, is_waiting 属性是 true )。

(2)对于二级索引记录来说本身并没有 trx_id 隐藏列,在二级索引页面的 Page Header 部分有一个 PAGE_MAX_TRX_ID 属性,该属性代表对该页面做改动的最大的 事务id ,如果 PAGE_MAX_TRX_ID 属性值小于当前最小的活跃 事务id ,那么说明对该页面做修改的事务都已经提交了则此时其他事务直接可以对该记录添加 S锁 或者 X锁, 否则就需要在页面中定位到对应的二级索引记录,然后回表找到它对应的聚簇索引记录,然后再根据该条聚簇索引的trx_id找到这条记录目前所在事务,则会为该事务创建一个 X锁结构,并且自己也创建一个进入等待状态。

其他

全局锁

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

死锁

概念:在MySQL中,当多个事务同时请求相同的资源时,可能会发生死锁。死锁是指两个或多个事务互相等待对方释放资源,导致所有事务都无法继续执行的情况。

实际处理
(1)第一种策略,直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout 来设置。
(2)第二种策略,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务(将持有最少行级排他锁的事务进行回滚),让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为on ,表示开启这个逻辑。

第二种策略成本分析
(1)如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉。但是这种操作本身带有一定的风险,因为业务设计的时候一般不会把死锁当做一个严重错误,毕竟出现死锁了,就回滚,然后通过业务重试一般就没问题了,这是 业务无损 的。而关掉死锁检测意味着可能会出现大量的超时,这是业务有损 的。
(2)控制并发度。如果并发能够控制住,比如同一行同时最多只有10个线程在更新,那么死锁检测的成本很低。基本思路就是,对于相同行的更新,在进入引擎之前排队,这样在InnoDB内部就不会有大量的死锁检测工作了

避免死锁

  1. 尽量减少事务的持有时间,尽快释放锁。
  2. 尽量减少事务中需要锁定的资源数量,避免同时请求相同的资源。
  3. 尽量按照相同的顺序请求资源,避免交叉锁定。
  4. 使用合适的隔离级别,例如使用READ COMMITTED隔离级别可以减少死锁的发生。
  5. 对于复杂的事务,可以使用分布式事务管理器来协调多个事务的操作,避免死锁的发生。

四、锁内存结构

五、锁监控

至此,《MySQL是怎样运行的:从根儿上理解MySQL》,复习结束!

工作面试老大难 - 锁相关推荐

  1. 前端工作面试问题(下)

    续 "前端工作面试问题(上)" JS相关问题: 解释下事件代理. 在传统的事件处理中,你按照需要为每一个元素添加或者是删除事件处理器.然而,事件处理器将有可能导致内存泄露或者是性能 ...

  2. 软件开发面试_如何为成功的软件开发工作面试做准备

    软件开发面试 Job interviews are stressful for many people. Besides the pressure of getting hired, you have ...

  3. [转载]工作面试时最难的25个问题

    原文地址:工作面试时最难的25个问题作者:zcan 准备是成功的一半 如果你是一个对目前的职位不满意,正着手去在新的一年里找到一个新的职位,这篇文章就是你的一个帮手.工作面试是你去面对未来的老板的征途 ...

  4. 分布式面试 - 分布式锁的常见问题

    分布式面试 - 分布式锁的常见问题 面试题 一般实现分布式锁都有哪些方式?使用 redis 如何设计分布式锁?使用 zk 来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高? 面试官心理分析 ...

  5. 程序开发,面试恐惧症_如何克服恐惧并停止讨厌的工作面试

    程序开发,面试恐惧症 by Reuben Reyes 由鲁本·雷耶斯(Reuben Reyes) 如何克服恐惧并停止讨厌的工作面试 (How to conquer your fear and stop ...

  6. 工作面试时最难的25个问题

    准备是成功的一半 如果你是一个对目前的职位不满意,正着手去在新的一年里找到一个新的职位,这篇文章就是你的一个帮手.工作面试是你去面对未来的老板的征途中最重要的一个过程.你必须像进行一个击剑锦标赛或着一 ...

  7. 前端工作面试问题(上)---转

    前端工作面试问题(上) 前段时间专心整理一下关于前端的面试问题.感谢耐心尽责的楷豪和闻东师兄最近给我们的指导和建议.大家可以通过这些问题,大家可以顺便看以下自己的水平. https://github. ...

  8. 啥?以后找工作面试求职者的将不是人!那是啥?道翰天琼认知智能机器人平台API接口为您揭秘。

    啥?以后找工作面试求职者的将不是人!那是啥?道翰天琼认知智能机器人平台API接口为您揭秘. 当你正襟危坐在屏幕前,参加公司视频面试的时候,此时盯着你的不仅是面试官,还有背后一整套 AI 算法. 你的表 ...

  9. 常见英语面试问答_40个常见的工作面试问答

    常见英语面试问答 Every job interview has some common questions that you should be prepared to answer. Having ...

最新文章

  1. Fescar 发布 0.3.0 版本, 支持 Eureka 注册中心
  2. Typora 收费,WTF? 还是需要支持下
  3. Linux下编译cscope,linux环境下cscope使用
  4. Linux-Learning
  5. php mysql主从延迟_如何解决主从数据库同步延迟问题?php连接 mysql 数据库如何添加一个公共的配置文件50...
  6. python取反函数_Python优雅的反函数int(string,base)
  7. 易成新能加码光伏产业链 作价28.29亿收购赛维两子公司
  8. UITableView 系列一 :基本使用方法 (显示,删除,添加图片,添加样式等) (实例)...
  9. 实验8 群体类、流类库与输入/输出(4学时)
  10. 7.3通过JVM来监控Spring Boot
  11. AtCoder Beginner Contest 083
  12. Java 7:最新特性更新、代码示例及性能测试
  13. Tensorflow游乐场
  14. 三点估算 Sigma(σ)的值,期望值,标准差
  15. 地图染色(四色定理)问题
  16. 提高元认知能力时刻掌握方向舵主动控制生命航向
  17. Java 实现四位数的吸血鬼算法
  18. oracle blob 照片,要在oracle里面存入图片 用 blob类型
  19. 摄像头的像素与分辨率之间的关系
  20. 如何用织梦仿制php网站首页,DEDE织梦网站首页(排名)仿制实战操作

热门文章

  1. Magento编译模式 - Magento Compiler Mode
  2. 1522 N 叉树的直径
  3. 社交软件撬TX墙角,到底还有没有汤喝
  4. win7查找计算机图片,win7系统查看图片分辨率的详细办法
  5. 1.Hive系列之简介
  6. 浅谈浏览器的兼容性(从HTML、CSS、JS、PC端、移动端等方面)
  7. 开发app要用html吗,为什么要使用HTML5开发手机APP?
  8. java中驼峰转大写,大写转驼峰
  9. 外贸中16种最重要的客户服务技能
  10. android webview 刷新当前页面,Android WebView时重新加载导致页面刷新的问题