MySql数据库MVCC和锁机制

MySQL中的MVCC机制

什么是MVCC

MVCC,全称 Multi-Version Concurrency Control ,即多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。(百度百科)

简而言之,一份数据可能存在多个版本。

快照读/当前读

  • 当前读:读取记录数据的最新版本(有锁)
    insert/update/delete/select…for update/select…in share mode
  • 快照读:读取记录数据的可见版本(最新版本/历史版本 无锁)
    select column/* from table

一条sql记录的结构

一条完整的记录可以被分为记录的额外信息和记录的真实数据。
在这里插入图片描述

  • row_id:隐含的自增 ID(隐藏主键),如果数据表没有主键,InnoDB 会自动产生一个聚簇索引

  • transaction_id:最近修改(修改/插入)事务 ID,记录创建这条记录/最后一次修改该记录的事务 ID(自增)

  • roll_pointer:回滚指针,指向这条记录的上一个版本

事务回滚是怎么回事呢?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Read View 读视图

Read View 就是事务进行快照读操作的时候生产的读视图 (Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的 ID (当每个事务开启时,都会被分配一个 ID , 这个 ID 是递增的,所以最新的事务,ID 值越大),Read View 主要是用来做可见性判断。

接下来需要记住几个重要的点:
在这里插入图片描述

拆解可见性算法的逻辑

  1. DB_TRX_ID < up_limit_id
    判断为true,则说明:快照生成时,所有比up_limit_id小的事务全部提交。也就是说,所有活跃事务的快照读读取的版本是最新的,大于等于进入下一个判断。
  2. DB_TRX_ID >= low_limit_id
    判断为true,则说明:快照生成时,所有活跃id的读取的数据版本是历史数据版本,如果小于则进入下一个判断。
  3. 判断 DB_TRX_ID 是否在活跃事务之中
    判断为true,则说明:Read View 生成时刻,这个事务还在活跃,还没有 Commit,修改的数据,当前事务也是看不见的;
    判断为false,则说明,你这个事务在 Read View 生成之前就已经 Commit 了,你修改的结果,我当前事务是能看见的

    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

MySQL中的锁

一个数据库的基本结构

在这里插入图片描述

MySQL数据库中的基本锁类型

  • 全局锁:全局锁就是对整个数据库实例加锁。

场景:当你需要整个数据库处于只读状态的时候,如全库逻辑备份。此过程中会阻塞所有的DDL和除了select的DML语句。
表锁的主动加锁语句:Flush tables with read lock(unlock解锁)

  • 表级锁:MySQL 里面表级别的锁有两种,一种是表锁,一种是元数据锁。

表锁的主动加锁语句:lock tables … read/write(unlock解锁),但是不建议使用。
元数据锁:不需要显式使用,在访问一个表的时候会被自动加上,保证读写的正确性。

元数据锁的场景:如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果跟表结构对不上。因此,在
MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。

  • 页级锁:页级锁定是MySQL中比较独特的一种锁定级别,特点是锁定颗粒度介于行级锁定与表级锁之间。

无具体使用场景。使用页级锁定的主要是BerkeleyDB存储引擎。

  • 行级锁:行锁就是针对数据表中行记录的锁。
  • 问题1:下面的两个语句锁的类型是什么?
    (1)update … where id = 1 (id为索引项)
    (2)update … where name = ‘a’ (name不是索引项)

  • 问题2:下面的两个语句存在锁竞争么?(type 为索引项)
    (1)update … where type = 1 and name = ‘1’
    (2)update … where type = 1 and name = ‘2’

  • 问题3:(1) 与(2)可能会有锁冲突么?(type/name 均为索引项)
    (1)update … where type = 1
    (2)update … where name = ‘1’
    ·········································································································································

  • 知识点1:
    InnoDB行锁是通过给索引上的索引项加锁来实现的。只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。

  • 知识点2:
    MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。

  • 知识点3:
    当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行。 这种情况是可能存在锁冲突的。

  • 间隙锁
    间隙锁是封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。
    打开间隙锁:show variables like ‘innodb_locks_unsafe_for_binlog’ 修改为off则开启间隙锁。
    在这里插入图片描述

假设间隙锁生效,锁定的区间为 (-supernum,5](5,10](10,15](15,20](20,+supernum]

  • 间隙锁只有在事务隔离级别 RR 中才会产生;

  • 唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁;

  • 普通索引不管是锁住单条,还是多条记录,都会产生间隙锁;

  • 间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,这是为了防止出现 幻读 现象;

  • 普通索引的间隙,优先以普通索引排序,然后再根据主键索引排序(多普通索引情况还未研究);

  • 事务级别是RC(读已提交)级别的话,间隙锁将会失效。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值