转自:https://blog.csdn.net/qq_35246620/article/details/69943011

refer:cnblogs.com/f-ck-need-u/p/8995475.html

在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足。

数据库的锁机制中,咱们介绍过在 DBMS 中,可以按照锁的粒度把数据库锁分为行级锁(InnoDB 引擎)、表级锁(MyISAM 引擎)和页级锁(BDB 引擎)。

行级锁

行级锁是 MySQL 中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突,其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁。

特点

开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

表级锁

表级锁是 MySQL 中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分 MySQL 引擎支持。最常使用的 MyISAM 与 InnoDB 都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。

特点

开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。

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

表锁的语法是 lock tables … read/write。与 FTWRL 类似,可以用 unlock tables 主动释放锁,也可以在客户端断开的时候自动释放。需要注意,lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。举个例子, 如果在某个线程 A 中执行 lock tables t1 read, t2 write; 这个语句,则其他线程写 t1、读写 t2 的语句都会被阻塞。同时,线程 A 在执行 unlock tables 之前,也只能执行读 t1、读写 t2 的操作。连写 t1 都不允许,自然也不能访问其他表。在还没有出现更细粒度的锁的时候,表锁是最常用的处理并发的方式。而对于 InnoDB 这种支持行锁的引擎,一般不使用 lock tables 命令来控制并发,毕竟锁住整个表的影响面还是太大。

另一类表级的锁是 MDL(metadata lock)。MDL 不需要显式使用,在访问一个表的时候会被自动加上。MDL 的作用是,保证读写的正确性。你可以想象一下,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。因此,在 MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。

MDL锁和表锁是两个不同的结构。

比如:
你要在myisam 表上更新一行,那么会加MDL读锁和表的写锁;
然后同时另外一个线程要更新这个表上另外一行,也要加MDL读锁和表写锁。

页级锁

页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。因此,采取了折衷的页级锁,一次锁定相邻的一组记录。BDB 支持页级锁。

特点

开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

MySQL 常用存储引擎的锁机制

  • MyISAM 和 Memory 采用表级锁(table-level locking)
  • BDB 采用页级锁(page-level locking)或表级锁,默认为页级锁;
  • InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。

InnoDB 中的行锁与表锁

前面提到过,在 InnoDB 引擎中既支持行锁也支持表锁,那么什么时候会锁住整张表?什么时候只锁住一行呢?

InnoDB 行锁是通过给索引上的索引项加锁来实现的,这一点 MySQL 与 Oracle 不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB 这种行锁实现的特点意味着:只有通过索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁。

在实际应用中,要特别注意 InnoDB 行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。

  • 在不通过索引条件查询的时候,InnoDB 确实使用的是表锁,而不是行锁。
  • 由于 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,因此虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。应用设计的时候要注意这一点。
  • 当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引还是普通索引,InnoDB 都会使用行锁来对数据加锁。
  • 即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同的执行计划的代价来决定的。如果 MySQL 认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下 InnoDB 将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查 SQL 的执行计划,以确认是否真正使用了索引。

行级锁与死锁

MyISAM 中是不会产生死锁的,因为 MyISAM 总是一次性获得所需的全部锁,要么全部满足,要么全部等待。而在 InnoDB 中,锁是逐步获得的,就造成了死锁的可能。

在 MySQL 中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条 SQL 语句操作了主键索引,MySQL 就会锁定这条主键索引;如果一条 SQL 语句操作了非主键索引,MySQL 就会先锁定该非主键索引,再锁定相关的主键索引(不存在索引覆盖的情况下,如果是索引覆盖,则不再锁定主键)。 在进行UPDATEDELETE操作时,MySQL 不仅锁定WHERE条件扫描过的所有索引记录,而且会锁定相邻的键值,即所谓的next-key locking.

当两个事务同时执行,一个锁住了主键索引,在等待其他相关索引;另一个锁定了非主键索引,在等待主键索引。这样就会发生死锁。

发生死锁后,InnoDB 一般都可以检测到,并使一个事务释放锁回退,另一个获取锁完成事务。

解决幻读用的引入了间隙锁(next-key lock 是行锁 record lock 和间隙锁gap lock的结合体):

我总结的加锁规则里面,包含了两个“原则”、两个“优化”和一个“bug”。

原则 1:加锁的基本单位是 next-key lock。希望你还记得,next-key lock 是前开后闭区间。

原则 2:查找过程中访问到的对象才会加锁。

优化 1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。

优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁。

一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。

https://time.geekbang.org/column/article/75659?utm_campaign=guanwang&utm_source=baidu-ad&utm_medium=ppzq-pc&utm_content=title&utm_term=baidu-ad-ppzq-title

避免死锁的方法

有多种方法可以避免死锁,这里只介绍常见的三种:

  1. 如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低发生死锁的可能性;
  2. 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
  3. 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率。

详述 MySQL 中的行级锁、表级锁和页级锁的更多相关文章

  1. [数据库事务与锁]详解五: MySQL中的行级锁,表级锁,页级锁

    注明: 本文转载自http://www.hollischuang.com/archives/914 在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的 ...

  2. 【数据库】数据库的锁机制,MySQL中的行级锁,表级锁,页级锁

    转载:http://www.hollischuang.com/archives/914 数据库的读现象浅析中介绍过,在并发访问情况下,可能会出现脏读.不可重复读和幻读等读现象,为了应对这些问题,主流数 ...

  3. MySQL中的行级锁,表级锁,页级锁

    在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足. 在数据库的锁机制中介绍过,在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引 ...

  4. 【转】MySQL中的行级锁,表级锁,页级锁

    在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足. 在数据库的锁机制中介绍过,在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引 ...

  5. 转 MySQL中的行级锁,表级锁,页级锁

      对mysql乐观锁.悲观锁.共享锁.排它锁.行锁.表锁概念的理解 转载. https://blog.csdn.net/puhaiyang/article/details/72284702 实验环境 ...

  6. MYSQL中约束及修改数据表

    MYSQL中约束及修改数据表 28:约束约束保证数据的完整性和一致性约束分为表级约束和列级约束约束类型包括:    NOT NULL(非空约束)    PRIMARY KEY(主键约束)    UNI ...

  7. C# 利用mysql.data 在mysql中创建数据库及数据表

    C# 利用mysql.data 在mysql中创建数据库及数据表 using System; using System.Collections.Generic; using System.Linq; ...

  8. Navicat使用教程:获取MySQL中的行数(第1部分)

    下载Navicat Premium最新版本 Navicat Premium是一个可连接多种数据库的管理工具,它可以让你以单一程序同时连接到MySQL.Oracle及PostgreSQL数据库,让管理不 ...

  9. mysql 中实现行变列

    前言: mysql行列变化,最难的就是将多个列变成多行,使用的比较多的是统计学中行变列,列变行,没有找到现成的函数或者语句,所以自己写了存储过程,使用动态sql来实现,应用业务场景,用户每个月都有使用 ...

随机推荐

  1. 微信小程序云开发-数据库-查询满足条件的数据

    一.查询价格大于10的商品 1.wxml文件 2.js文件 where条件语句:.where({price:db.command.gt(10)}) 3.查询结果 二.查询价格大于等于10的商品 js文 ...

  2. 【NOIP2007】Hanoi双塔问题

    题目描述 给定A.B.C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形). 现要将这些圆盘移到C柱上 ...

  3. 完整的URL是怎样的?

    完整的URL字段解读: URL:http://localhost:80/MzyPractice/chapter10/testb.php?name=Mei&radio=Test#dowel ht ...

  4. Hive开发要知道数据仓库的四个层次设计

    数据仓库:数据仓库全面接收源系统数据,ETL进程对数据进行规范化.验证.清洗,并最终装载进入数据集市,通过数据集市支持系统进行数据查询.分析,整个数据仓库包含四大层次. 1.数据仓库的四个操作    ...

  5. .net 5+ 知新:【2】 .Net Framework 、.Net 、 .NET Standard的概念与区别

    作为了解历史和眼睛或者过程,我们需要将 .Net Framwork ..Net. .Net Stander几个概念进行下理解. .net 代表跨平台框架,从.net 5开始就统一叫.net,废弃原来的 ...

  6. 【用例】编写App测试用例的关注点

    编写App测试用例的关注点 如何做到测试用例的百分百覆盖一直是测试用例编写过程中的难点,首先在测试时我们经常会遇见一些常见的bug,那么我们可以在编写测试用例时考虑到这些点.    一:关于业务逻辑 ...

  7. 解决Docker安装慢

    之前介绍了Ubuntu安装Docker教程,在实际安装过程中,可能受限于国内网络问题,安装缓存或者失败.下面介绍一种通过国内镜像方式,仅需要执行一段脚本即可大幅度提升Docker的安装速度. Linu ...

  8. java顺序结构、循环结构、选择结构

    java顺序结构.选择结构.循环结构 顺序结构: 语句与语句之间,框与框之间是从上到下的顺序进行的,它是由若干个依次执行的处理步骤执组成的,它是任何一个算法都不离开的一种基本算法结构. 选择结构: 1 ...

  9. DC-2 靶机渗透测试

    DC-2 靶机渗透测试 冲冲冲,好好学习. 本靶机核心内容"受限shell提权",知识点在另一篇文章中总结归纳了. 攻击机:kali 靶 机:DC-2 准备:在使用前需要在操作机的 ...

  10. scrapy 使用crawlspider rule不起作用的解决方案

    一直用的是通用spider,今天刚好想用下CrawlSpider来抓下数据.结果Debug了半天,一直没法进入详情页的解析逻辑.. 爬虫代码是这样的 # -*- coding: utf-8 -*- i ...