Mysql锁详解

01 | Mysql事物

1.1 ACID
  • 1、 原子性(Atomicity) :事务是一个原子操作单元,对数据的修改,要么全都执行,要么全都不执行。
  • 2、 一致性(Consistency) :指的是事务开始之前和事务结束之后,数据库的完整性限制未被破坏。一致性包括两方面的内容,分别是约束一致性和数据一致性。
  • 3、 隔离性(Isolation) :指的是一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对其他的并发事务是隔离的。
  • 4、持久性(Durability) :指的是一个事务一旦提交,它对数据库中数据的改变就应该是永久性的,后续的操作或故障不应该对其有任何影响,不会丢失。
1.2 MVCC(Multi Version Concurrency Control)

MVCC:多版本并发控制,是指在数据库中为了实现高并发的数据访问,对数据进行多版本处理,并通过事务的可见性来保证事务能看到自己应该看到的数据版本。MVCC使用的是Copy on Write的思想,支持读读、读写、写读的并行处理。

实现原理

MVCC最大的好处是读不加锁,读写不冲突。在读多写少的系统应用中,读写不冲突是非常重要的,极大的提升系统的并发性能,这也是为什么现阶段几乎所有的关系型数据库都支持 MVCC 的原因,不过目前MVCC只在 Read Commited 和 Repeatable Read 两种隔离级别下工作。
在 MVCC 并发控制中,读操作可以分为两类: 快照读(Snapshot Read)与当前读 (Current Read)。

  • 快照读:读取的是记录的快照版本(有可能是历史版本),不用加锁。(select)
  • 当前读:读取的是记录的最新版本,并且当前读返回的记录,都会加锁,保证其他事务不会再并发修改这条记录。(select… for update 或lock in share mode,insert/delete/update)
1.3 事物隔离级别
事物隔离级别脏读不可重复读幻读
读未提交可能发生可能发生可能发生
读已提交X可能发生可能发生
可重复读XX可能发生
串行化XXX
  • 读未提交(Read Uncommitted):解决了回滚覆盖类型的更新丢失,但可能发生脏读现象,也就是可能读取到其他会话中未提交事务修改的数据。
  • 读已提交(Read Committed)(Oracle、SQLServer默认隔离级别) :只能读取到其他会话中已经提交的数据,解决了脏读。但可能发生不可重复读现象,也就是可能在一个事务中两次查询结果不一致。
    可重复度
  • 可重复读(Repeatable Read)(mysql默认隔离级别) :解决了不可重复读,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上会出现幻读,简单的说幻读指的的当用户读取某一范围的数据行时,另一个事务又在该范围插入了新行,当用户在读取该范围的数据时会发现有新的幻影行。
    可串行化
  • 串行化(Serializable):所有的增删改查串行执行。它通过强制事务排序,解决相互冲突,从而解决
    幻度的问题。这个级别可能导致大量的超时现象的和锁竞争,效率低下。
Mysql隔离级别控制
-- 查看当前隔离级别
show variables like 'tx_isolation';
-- 设置隔离级别
set tx_isolation='READ-UNCOMMITTED';
set tx_isolation='READ-COMMITTED';
set tx_isolation='REPEATABLE-READ';
set tx_isolation='SERIALIZABLE';

02 | 锁机制

2.1 锁分类
按操作粒度可分为:
  • 表级锁:每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM、InnoDB、BDB 等存储引擎中。
  • 行级锁:每次操作锁住一行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB 存储引擎中。
  • 页级锁:每次锁定相邻的一组记录,锁定粒度界于表锁和行锁之间,开销和加锁时间界于表锁和行锁之间,并发度一般。应用在BDB 存储引擎中。
存储引擎表锁页锁行锁
InnoDB支持X支持
MyISAM支持XX
BDB支持支持X
按操作类型可分为:
  • 读锁(S锁):共享锁,针对同一份数据,多个读操作可以同时进行而不会互相影响。
  • 写锁(X锁):排他锁,当前写操作没有完成前,它会阻断其他写锁和读锁。
按操作性能可分为:
  • 乐观锁:一般的实现方式是对记录数据版本进行比对,在数据更新提交的时候才会进行冲突检测,如果发现冲突了,则提示错误信息。
  • 悲观锁:在对一条数据修改的时候,为了避免同时被其他人修改,在修改数据之前先锁定,再修改的控制方式。共享锁和排他锁是悲观锁的不同实现,但都属于悲观锁范畴。
2.2 行锁原理

InnoDB行锁是通过对索引数据页上的记录加锁实现的,即使用行锁的前提是建立索引,主要实现算法有以下3种:

  • 行锁(RecordLock):锁定单个行记录的锁,分为读锁和写锁,如下表(RC、RR隔离级别都支持)
读锁写锁
读锁兼容冲突
写锁冲突冲突

注:这里读锁写锁冲突是指当前读锁,而不是MVCC中的快照读锁

  • 间隙锁(Gap Lock):间隙锁,锁定索引记录间隙,确保索引记录的间隙不变,根间隙锁存在冲突关系的是“往这个间隙中插入一个记录”这个操作,换句话说就是间隙锁只会影响insert操作而不会影响updateselect操作,间隙锁的引入是为了解决幻读问题,但需要锁住更大的范围,降低了并发读。(注:间隙锁只有在RR隔离级别下才会生效,如果把隔离级别设置为读提交,就没有间隙锁了,但同时,可能会出现数据和日志不一致的情况,需要将binlog的格式设置为row)

  • Next-key Lock 锁:记录锁和间隙锁组合,同时锁住数据,并且锁住数据前后范围,next-key lock 是前开后闭区间。(RR隔离级别支持)

加锁的基本规则:
  • 1、加锁的基本单位是 next-key lock
  • 2、查找过程中访问到的对象才会加锁
  • 3、索引上的等值查询,给唯一索引加锁的时候,若记录存在next-key lock 则退化为行锁
  • 4、索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁。唯一索引上的范围查询会访问到不满足条件的第一个值为止。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值