MySQL锁机制知识点

锁概述

  • 锁机制用于管理对共享资源的并发访问。InnoDB存储引擎会在行级别上对表数据上锁,也会在数据库内部其他多个地方使用锁,从而允许多种不同资源提供并发访问。数据库使用锁是为了支持对共享资源进行并发访问,保持数据的完整性和一致性
  • InnoDB存储引擎锁的实现和Oracle数据库非常类似,提供一致性的非锁定读、行级锁支持。行级锁没有相关额外的开销,并可以同时得到并发性和一致性
  • 缺点:加锁是消耗资源的,锁的各种操作,包括获得锁、检测锁是否已解除、释放锁等,都会增加系统的开销。

锁分类

锁粒度表锁页锁行锁;特殊场景下有全局锁
在这里插入图片描述

  • 表锁:对整张表加锁,锁粒度大,锁冲突的概率高,并发度低;但开销小,加锁快;不会出现死锁

  • 行锁:对一行数据加锁,锁粒度小,锁冲突概率低,并发性高;但开销大,加锁慢;会出现死锁。

    前提条件:索引。因为InnoDB是通过给索引的索引项加锁来实现行锁的。否则使用表锁

  • 页锁:锁粒度介于表锁和行锁之间,并发度一般;开销和加锁速度介于表锁和行锁之间;会出现死锁。主要应用于BOB存储引擎

兼容性: 共享(读)锁排他(写)锁意向共享(读)锁意向排他(写)锁
在这里插入图片描述

  • 共享锁S: 又称读锁。多个读操作可以同时进行,但会阻塞其他写操作。
  • 排他锁X: 又称写锁。会阻塞其他事务的读写操作(只能当前事务进行读写)。
  • 意向共享锁IS: 事务在给一个数据行加S锁前必须先取得该表的IS锁。
  • 意向排他锁IX: 事务在给一个数据行加X锁前必须先取得该表的IX锁。

意向锁 都是表锁,不会与行级的共享锁/排他锁互斥。只会和表级的X,S发生冲突。
存在意义:一个事务尝试获得表的共享或排他锁时,只需检查表上的意向锁,不必一行一行检查行锁,提高效率。

行锁实现算法

Record Lock(记录锁): 锁住索引记录,如果没有设置索引,InnoDB会使用隐式的主键进行锁定。

Gap Lock(间隙锁): 锁定一个范围,但不包含记录本身。

  • 针对的隔离级别为可重复读或以上。
  • InnoDB中唯一作用是Next-Key Lock来解决幻读问题。

Next-Key Lock(临建锁): 锁定一个范围,并且包含记录本身(左开右闭),行锁+间隙锁。

  • InnoDB使用Next-Key Lock 来解决幻读问题。
  • 当查询的索引为主键索引或唯一索引时,Next-Key Lock会降级为Record Lock
  • 当查询的索引为辅助索引时,使用Next-Key Lock锁住辅助索引值所在的范围,还会将其下一键值加上Gap Lock

如何上锁

普通SELECT语句,InnoDB不会加任何锁,可以通过以下语句显示加锁

  • 共享锁S:SELECT * FROM table_name WHERE … LOCK IN SHARE MODE。用于需要数据依存关系时来确认某行记录是否存在, 并确保没有人对记录进行UPDATE或者DELETE操作。但如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁
  • 排他锁X:SELECT * FROM table_name WHERE … FOR UPDATE。用于锁定行记录后需要进行更新操作的应用

UPDATE、DELETE和INSERT写操作,InnoDB会自动给涉及数据集加排他锁X;

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

一致性非锁定读和一致性锁定读

一致性非锁定读(快照读)

  • 一致性非锁定读是指InnoDB存储引擎通过行多版本控制(MVCC)的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此去等待行上锁的释放。相反InnoDB存储引擎会去读取一个快照数据。读取快照数据是不需要上锁的,因为没有事务需要对历史的数据进行修改操作。
  • 之所以称为非锁定度,是因为不需要等待访问数据行上的X锁的释放。快照数据是指该行之前版本的数据,通过undo段来实现(undo用来在事务中回滚数据)。
  • 非锁定读机制极大地提高了数据库的并发性,在InnoDB存储引擎这是默认的读取方式,即读取不会占用和等待表上的锁。但是在不同事务隔离级别下,读取的方式不同 ,并不是在每个事务隔离级别下都采用非锁定的一致性读
  • Read CommittedRepeatable Read模式下,innodb存储引擎使用默认的一致性非锁定读。在Read Committed隔离级别下,对于快照数据,一致性非锁定读总是读取被锁定行的最新一份快照数据;而在Repeatable Read隔离级别下,对于快照数据,一致性非锁定读总是读取事务开始时的行数据版本。

一致性锁定读(当前读)

  • 在某些情况下用户需要显式地对数据库读取操作进行加锁以保证数据逻辑的一致性,而这要求数据库支持加锁语句,InnoDB存储引擎对于SELECT语句支持两种一致性的锁定读操作
    • SELECT…FOR UPDATE 对于读取的行记录加一个X排它锁,其他事务不能对锁定的行加任何锁。
    • SELECT…LOCK IN SHARE MODE 对于读取的行记录添加一个S共享锁。其它事务可以向被锁定的行加S锁,但是不允许添加X锁,否则会被阻塞。

MVCC

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

MVCCMySQL InnoDB 中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突(这里读为快照读),做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。

MVCC能解决什么问题?
在这里插入图片描述
在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。

同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题。

MVCC实现原理

主要是依赖记录中的 3个隐式字段undo日志Read View 来实现的。

  • 隐藏字段:每行记录除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID, DB_ROLL_PTR, DB_ROW_ID 等字段
  • 基于undo log的版本链:每条undo log 也会指向更早版本的undo log,从而形成一条版本链。
  • ReadView:主要用来做可见性判断的。 Read View 就是事务进行快照读操作的时候生产的读视图 ,记录并维护系统当前活跃事务的 id,将其放到一个名为m_ids的列表中。(当每个事务开启时,都会被分配一个 ID , 这个 ID 是递增的,所以最新的事务,ID 值越大)
    • 被访问版本的 trx_id 小于 m_ids 中最小事务id(低水位),说明生成该版本的事务在生成 ReadView 前已提交 可见
    • 被访问版本的 trx_id 大于 m_ids 中最大事务id(高水位),说明生成该版本的事务在生成 ReadView 后才生成 不可见
    • 被访问版本的 trx_id 在 m_ids 中最大事务id和最小事务id之间,则继续判断 trx_id 属性值是否在 m_ids 中。如果在,说明该版本的事务活跃,该版本对当前事务不可见;如果不在,说明该版本的事务已经被提交 可见

死锁

什么是死锁?
死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。
常见的死锁解决方法

  • 单次操作数据量不宜过多,涉及表尽量少
  • 精心设计索引,尽量使用索引访问数据
  • 减少表上索引,减少锁定资源
  • 尽量基于primary(主键)或unique key更新数据
  • 尽量使用较低的隔离级别
  • 尽量使用相同条件访问数据,避免间隙锁对并发的插入影响
  • 多个程序尽量约定以相同的顺序访问表
  • 同一个事务中尽可能做到一次锁定所需要的所有资源
  • 尝试使用升级锁定颗粒度,通过表锁来减少死锁产生概率。

乐观锁和悲观锁

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
在这里插入图片描述

  • 悲观锁: 假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。适用于多写的应用场景来减少冲突
    实现方式:使用数据库中的锁机制。如行锁,表锁;读锁,写锁等
  • 乐观锁: 假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。适用于读多写少的应用场景来提高吞吐量。
    实现方式:乐观锁一般会使用版本号机制CAS算法实现。

参考

  • https://chensj.blog.csdn.net/article/details/115864190
  • https://learnku.com/articles/39212
  • https://zhuanlan.zhihu.com/p/66676020
  • https://blog.csdn.net/lm1060891265/article/details/81484033
  • https://blog.csdn.net/SnailMann/article/details/94724197
  • https://mp.weixin.qq.com/s/yWpFX-OUXlfZpiDz4GjVUw
  • https://javaguide.blog.csdn.net/article/details/81072874
  • https://javaguide.blog.csdn.net/article/details/81252853
  • https://www.jianshu.com/p/dab1c0ecbac0
  • https://blog.csdn.net/qq_42914528/article/details/103790555
  • https://zhuanlan.zhihu.com/p/296545804
  • https://juejin.cn/post/6844903666332368909#heading-1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值