MySql锁与InnoDB引擎

MySql锁与InnoDB引擎

mysql的锁是面试中很高频问题,也是我们在日常开发中经常会遇到但是我们并没有注意到的地方。我把我自己理解的锁通过本篇博文分享出来,由于锁需要结合事务来理解,本文只介绍锁的基本概念,同样为了理解事务会更加深刻,先介绍了InnoDB的一些基础概念,也是记录自己的学习,欢迎大家一起探讨交流。

下一篇:mysql的事务与mvcc

锁的分类:

  • 按照锁的粒度来分

    • 全局锁: 锁的是整个database,类比一个库为一栋大楼,那此时就是锁的整栋楼的大门
    • 表级锁: 锁的是某个table,类比一个表为大楼的某一层,此时锁的就是某一层整层
    • 行级锁:锁的是某一行数据,类比每行锁的是某一层的某一间房间,此时锁的是某一个房间
  • 表锁和行锁的区别
    • 表级锁,开销大,加锁快,不会出现死锁。锁的粒度大。并发度低。
    • 行级锁,开销小,加锁慢,会出现死锁,锁的粒度小,并发度高。

表级锁:

mysql的表级锁有两种:元数据锁和表锁。

表锁的两种形式:

  • 表共享读锁
  • 表排它写锁
    • 手动加表锁

      lock table tableName read;
      
    • 查看表锁情况
      show open tables;
      
    • 删除表锁
      unlock tables;
      

元数据锁:

  • 5.5版本中引入了MDL,对一个表数据进行增删改的时候,加MDL读锁;要对表结构进行修改的时候,加MDL写锁。

行级锁

mysql的行级锁是有存储引擎实现的,mysql现在默认的数据引擎为Innodb。本文主要介绍InnoDB的行锁;

InnoDB的行锁是给索引项加锁实现的,也就意味着只有使用索引检索的数据才能使用行锁,否则将使用表锁。

按照范围来说

  • 行锁:锁定表中的某一条记录。
  • 间隙锁:
    • 锁住索引记录中间的值
    • 锁住第一个索引记录前面的值或者最后一个索引后面的值

按照功能来说

  • 共享锁,也叫做S锁:允许一个事务去读一行数据,阻止其他事务添加排它锁,允许继续添加共享锁读
  • 排它锁,也叫做X锁:允许获得排它锁的事务更新数据,阻止其他事务添加读共享锁和添加排它锁写

对于InnoDB来说,会自动给增删改语句添加排它锁,X锁。对于普通的查询语句不会添加任何锁。

意向锁

InnoDB同样也实现了表级锁,也就是意向锁。意向锁是mysql内部使用的,不需要用户去干预。

  • 意向共享锁,IS锁:事务打算给数据行加共享锁,事务在给一个数据行添加共享锁前必须获取该表的IS锁。
  • 意向排它锁,IX锁:事务打算给数据航加排它锁,事务在给一个数据行添加排它锁前必须获取该表的IX锁。

意向和行锁可以共存,意向锁的作用是为了提升全表更新数据时的性能提升,否则在更新全表时要检索哪些数据行上有行锁。

间隙锁

顾名思义,主要是在记录之间添加锁,不允许往间隙插入数据。比如id为 2 4,那此时使用间隙锁就会锁2 3 4 这三个,稍后在介绍事务的时候也会再次介绍间隙锁,间隙锁的主要作用就是为了解决幻读问题。此处先了解一下。

死锁

mysql的死锁和我们代码中死锁理论是一样的,不同的是,mysql指的是两个不同的连接互相等待对方释放锁,才能释放自己持有的资源,所以造成了死锁。mysql中也有对死锁的优化。我们稍后再具体说。

接下来我们开始介绍事务,上面只是简单介绍了一下锁的基本概念,锁还有一部分内容需要结合事务来理解,所以稍后还有锁的介绍。

在我们介绍事务之前,我们先聊一下InnoDB的架构,事务中的一些部分会涉及到这部分的内容。

InnoDB的磁盘文件

InnoDB的磁盘文件

  • 系统表空间

    • 系统表空是一个共享的表空间
    • 系统表空间包含数据字典、doule write buffer、change buffer、undo log的存储区域,包含用户在系统表创建的表结构和索引数据
  • 用户表空间
    • 设置参数 innodb_file_per_table ,用户就可以为每个基于InnoDB引擎的表创建一个独立的用户表空间,也就是.ibd文件。
    • 存储该表的数据、索引等信息。

InnoDB内存结构

  • buff pool 缓冲池

    • 数据是存储于磁盘的,由于cpu速度和磁盘速度的差别,所以使用缓冲池提高整体性能。
    • 通过innodb_buffer_pool_size可以设置缓冲池的大小,缓冲池的大小对性能也是有影响的。
    • 缓冲池中缓冲的数据类型:
      • 索引页
      • 数据页
      • 存储引擎工作时,需要以页为单位将磁盘数据加载到内存中,数据页和索引页是页类型中最重要的两种类型
      • undo页:实现了mysql多版本的快照,可以理解为版本链。mvcc和回滚操作都涉及到了undo日志。
      • insert buffer:提高了对于非聚簇索引的插入性能
      • 自适应哈希索引
      • InnoDB存储的锁信息
      • 数据字典信息

内存数据落盘

InnoDB数据落盘有图可以看出来是通过两种方式来实现的

  • 脏页数据落盘
  • 预写redo日志

通过两种方式来落盘,也可以理解为持久化到磁盘上。是为了保证数库发生突然宕机,造成数据丢失。

脏页落盘会产生IO并且是随机写入,耗时比较长。频繁进行磁盘IO对性能损耗是非常大。并且数据的安全性得不到保障。如果在脏页数据还没来得及落盘或者落盘过程出现宕机,那么数据就会丢失。

鉴于以上情况,mysql用双保险完成数据的安全性,脏页落盘是一种,另一种就是预写redo 日志,首先我们要知道redo 持久化到磁盘是顺序写入,顺序写入的速度要比随机写入要快,此时有朋友就会问,那脏页落盘为什么不采用顺序写入呢但?

顺序写入速度快的同时是会产生磁盘碎片的,磁盘碎片会大大浪费磁盘资源。

redo 日志持久化的时机是在事务提交时写入到磁盘的redo file中,此时脏页数据并不一定完成了落盘,脏页落盘是由checkPoint检查点机制控制的,我们这里不展开多说。

数据库发生宕机的情况:

  • 脏页数据未落盘,事务未提交,此时产生了数据丢失,我们都知道如果事务未提交换个角度来讲这些数据丢失是正常的。
  • 脏页数据未落盘,事务已提交,此时redo log file已经有了数据,那么重启的时候mysql就会从redo log file中进行数据恢复。

有的朋友还会说,那redo log file的数据岂不是无限大?

ib_logfile0,ib_logfile1 这是rodo log 在我们磁盘上的命名,可以看到有两个文件,采用的循环写入的方式,如果1满了就写入2,2满了写入1,这样循环。

redo 日志持久化到磁盘也是可以配置的,通过InnoDB的innodb_push_log_at_trx_commit来设置

  1. 属性值为0时,事务提交,不会对redo进行写入操作,等待主线程按时写入;
  2. 属性值为1时,事务提交,将数据写入磁盘,确保不会出现数据丢失;
  3. 属性值为2时,事务提交,将数据写入系统缓存,让文件系统自己判断什么时候写入磁盘。

默认值为1,一般也建议设置为1,会保证数据的安全性,并且只有为1的时候才会保证事务的一致性。


以上就是本篇博文的全部内容,感谢各位看官。欢迎提出问题一起交流探讨。

下一篇:mysql的事务和mvcc

原文地址:https://www.cnblogs.com/sx-wuyj/p/12540537.html

时间: 2024-11-08 18:58:35

MySql锁与InnoDB引擎的相关文章

MySQL系列:innodb引擎分析之线程并发同步机制

innodb是一个多线程并发的存储引擎,内部的读写都是用多线程来实现的,所以innodb内部实现了一个比较高效的并发同步机制.innodb并没有直接使用系统提供的锁(latch)同步结构,而是对其进行自己的封装和实现优化,但是也兼容系统的锁.我们先看一段innodb内部的注释(MySQL-3.23): Semaphore operations in operating systems are slow: Solaris on a 1993 Sparc takes 3 microseconds (

MySQL系列:innodb引擎分析之文件IO

innodb作为数据库引擎,自然少不了对文件的操作,在innodb中所有需要持久化的信息都需要文件操作,例如:表文件.重做日志文件.事务日志文件.备份归档文件等.innodb对文件IO操作可以是煞费苦心,其主要包括两方面,一个是对异步io的实现,一个是对文件操作管理和io调度的实现.在MySQL-5.6版本的innodb还加入了DIRECT IO实现.做了这么多无非是优化io操作的性能.在innodb的文件IO部分中,主要实现集中在os_file.*和fil0fil.*两个系列的文件当中,其中o

查看MySQL是否支持InnoDB引擎以及不支持的解决办法

通过命令行进入mysql SHOW variables like "have_%"; 显示结果中会有如下3种可能的结果: have_innodb YES have_innodb NO have_innodb DISABLED 这3种结果分别对应: 已经开启InnoDB引擎 未安装InnoDB引擎 未启用InnoDB引擎 对第二种未安装,只需要安装即可: 针对第三种未启用,则打开mysql配置文件,找到 skip-innodb项,将其改成#skip-innodb,之后重启mysql服务

mysql服务器参数--innodb引擎

mysql服务器参数有很多,如果想查看某一项参数的具体含义,可以使用mysqld --verbose --help | grep innodb存储引擎中的参数都是以innodb开头的: innodb_buffer_pool_size: 这个参数定义了innodb存储引擎的表数据和索引数据的最大内存缓冲区大小,和myisam存储引擎不同,myisam的key_buffer_size只缓存索引键,而innodb_buffer_pool_size却是同时为数据块和索引块做缓存,这个特性和oracle是

MySQL系列:innodb引擎分析之基础数据结构

近一年来一直在分析关于数据库相关的源码,前段时间分析了levelDB的实现和BeansDB的实现,这两个数据库网络上分析的文章很多,也都比较分析的比较深,所以也就没有太多必要重复劳动.最近开始关注关系数据库和MYSQL,当然主要还是数据库存储引擎,首先我还是从innodb这个最流行的开源关系数据库引擎着手来逐步分析和理解.我一般分析源码的时候都是从基础的数据结构和算法逐步往上分析,遇到不明白的地方,自己按照源码重新输入一遍并做对应的单元测试,这样便于理解.对于Innodb这样的大项目,也应该如此

推荐:mysql锁 innodb下的记录锁,间隙锁,next-key锁

你需要知道的 之前我们介绍了排他锁,其实innodb下的记录锁(也叫行锁),间隙锁,next-key锁统统属于排他锁. 行锁 记录锁其实很好理解,对表中的记录加锁,叫做记录锁,简称行锁. 生活中的间隙锁 编程的思想源于生活,生活中的例子能帮助我们更好的理解一些编程中的思想. 生活中排队的场景,小明,小红,小花三个人依次站成一排,此时,如何让新来的小刚不能站在小红旁边,这时候只要将小红和她前面的小明之间的空隙封锁,将小红和她后面的小花之间的空隙封锁,那么小刚就不能站到小红的旁边. 这里的小红,小明

mysql锁 innodb下的记录锁,间隙锁,next-key锁

你需要知道的之前我们介绍了排他锁,其实innodb下的记录锁(也叫行锁),间隙锁,next-key锁统统属于排他锁. 行锁记录锁其实很好理解,对表中的记录加锁,叫做记录锁,简称行锁. 生活中的间隙锁编程的思想源于生活,生活中的例子能帮助我们更好的理解一些编程中的思想.生活中排队的场景,小明,小红,小花三个人依次站成一排,此时,如何让新来的小刚不能站在小红旁边,这时候只要将小红和她前面的小明之间的空隙封锁,将小红和她后面的小花之间的空隙封锁,那么小刚就不能站到小红的旁边.这里的小红,小明,小花,小

MySQL系列:innodb引擎分析之内存管理

在innodb中实现了自己的内存池系统和内存堆分配系统,在innodb的内存管理系统中,大致分为三个部分:基础的内存块分配管理.内存伙伴分配器和内存堆分配器.innodb定义和实现内存池的主要目的是提供内存的使用率和效率,防止内存碎片和内存分配跟踪和调试.我们先来看看他们的关系和结构. 以下是它的关系结构图: 上图中的: ut_mem_block块是基础内存管理 Buddy allocator是内存伙伴分配器 mem_heap是内存堆分配器 1.基础内存管理 innodb中的内存分配和内存释放是

MySQL锁解决并发问题详解

文章分为以下几个要点 问题描述以及解决过程 MySQL锁机制 数据库加锁分析 下面讨论的都是基于MySQL的InnoDB. 0. 问题描述以及解决过程 因为涉及到公司利益问题,所以下面很多代码和数据库信息,进行了缩减和修改,望见谅. 业务场景是优惠券系统规则规定了一个优惠券活动最多可发行多少张优惠券和每个用户最多可领取优惠券数量. 下面列出两张表的结构. 活动表 CREATE TABLE `coupon_activity` ( `act_id` int(11) NOT NULL AUTO_INC