MySQL锁

MySQL锁

概述

不同存储引擎的锁机制:

  • MyISAM采用的是表级锁。
  • InnoDB既支持行级锁,也支持表级锁。InnoDB行锁是通过给索引项加锁来实现的,只有通过索引条件检索数据才会加行锁,在没有索引的情况下使用表锁。

表锁行锁特点:

  • 表锁:开销小,加锁快,不会出现死锁,锁粒度大,发生锁冲突的概率大,并发度低,适合查询场景。
  • 行锁:开销大,加锁慢,会出现死锁,发生锁冲突几率低,并发度高,适合大部分应用场景。

MyISAM

  • 表共享读锁(Table Read Lock):不会阻塞其他事务对同一表的读请求,但会阻塞对同一表的写请求;
  • 表独占写锁(Table Write Lock):会阻塞其他事务对同一表的读和写操作;

MyISAM在执行查询语句前,会自动给涉及的所有表加读锁,在执行更新操作前,会自动给涉及的表加写锁。

MyISAM支持并发插入,以减少给定表的读和写操作之间的争用:如果MyISAM表在数据文件中没有空闲块,则行始终插入数据文件的末尾。在这种情况下,可以自由混合并发使用MyISAM表的insert和select语句而不需要加锁—你可以在其他线程进行读操作的时候,同时将行插入到MyISAM表中。文件中的空闲块可能是从表格中间删除或者更新的行而产生的。如果文件中间有空闲块,则并发插入会被禁用。

InnoDB

  • 共享锁(S):允许一个事物去读一行,阻止其他事物获得相同数据集的排他锁。即多个事务可以同时读取同一个资源,但是不允许其他事务修改。
  • 排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的读锁和写锁。写锁是排他的,写锁会阻塞其他的写锁和读锁。

为了允许行锁和表锁共存,实现多粒度机制,InnoDB还有两种内部使用的意向锁:

  • 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须取得该表的IS锁。

  • 意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

    共享锁(S)排他锁(X)意向共享锁(IS)意向排他锁(IX)
    共享锁(s)兼容冲突兼容冲突
    排他锁(X)冲突冲突冲突冲突
    意向共享锁(IS)兼容冲突兼容兼容
    意向排他锁(IX)冲突冲突兼容兼容

    注意:上表的S,X都是表级的

    意向锁是InnoDB自动加的,不需要用户干预。

    使用意向锁的目的:https://www.zhihu.com/question/51513268

InnoDB的update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何类型锁。

间隙锁

当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做"间隙(GAP)",InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁。

很显然,在使用范围条件检索并锁定记录时,InnoDB这种加锁机制会阻塞符合条件范围内键值的并发插入,这往往会造成严重的锁等待。因此,在实际应用开发中,尤其是并发插入比较多的应用,我们要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。

InnoDB使用间隙锁的目的:
  • 防止幻读
  • 满足恢复和复制的需要

乐观锁与悲观锁

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。

MVCC

MVCC多版本并发控制,它是行级锁的变种。MVCC最大的优点是读不加锁,因此读写不冲突,并发性能好。InnoDB实现MVCC,多个版本数据可以共存,主要基于以下技术及数据结构:

  1. 隐藏列:InnoDB中每行数据都有隐藏列,隐藏列中包含了本行数据的事务id、指向undolog的指针等。
  2. 基于undolog的版本链:前面说到每行数据的隐藏列中包含了指向undolog的指针,而每条undolog也会指向更早版本的undo log从而形成一条版本链。
  3. ReadView:通过隐藏列和版本链,MySQL可以将数据恢复到指定版本;但是具体要恢复到哪个版本,则需要根据ReadView来确定。所谓ReadView,是指事务在某一时刻给整个事务系统打快照(trx_sys),之后再进行读操作是,会将读取到的事务中的事务id与trx_sys快照比较,从而判断数据对该ReadView是否可见。

简单说MVCC会给每行加创建版本号和删除版本号的字段,而每一个事务在开启的时候,都有一个唯一的递增的版本号。

  • SELECT

    • 读取创建版本小于或等于当前事务版本号,并且 删除版本 为空或大于当前事务版本号的记录。这样可以保证在读取之前记录是存在的
  • INSERT

    • 将当前事务的版本号保存至行的创建版本号
  • UPDATE

    • 新插入一行,并以当前事务的版本号作为新行的创建版本号,同时将原记录行的删除版本号设置为当前事务版本号
  • DELETE

    • 将当前事务的版本号保存至行的删除版本号
      MVCC:https://blog.csdn.net/qq_33330687/article/details/89004462
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值