MySQL-MVCC原理

MySQL-MVCC原理,第1张

MySQL-MVCC原理

文章目录

MySQL-MVVC

一、事务

简介事务特性事务可能出现的问题

事务问题的四种解决方案 事务控制语句:MYSQL 事务处理主要有两种方法: 二、InnoDB锁

行锁(共享锁与排它锁)

共享锁(Share Lock)排它锁(exclusive lock) 意向锁-表锁机别表锁自增锁InnoDB锁的实现方式

Next-key Lock 临键锁,InooDB行锁默认算法Gap Lock 间隙锁Record Lock 记录锁 死锁

避免死锁 三、MVCC多版本并发控制四、Undo log五、Redo log

**Redo Log 概念:**持久性配置持久性配置

MySQL-MVVC 一、事务 简介

只有Innodb数据库引擎支持事务事务处理维护数据库的完整性,保证成批的SQL语句要么全部执行,要么全部不执行事务用来管理insert、update、delete语句 事务特性

一般来说,事务是必须满足4个条件(ACID):原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。

    **原子性:**一个食物中的所有 *** 作,要么全部完成,要么全部不完成,不会结束在中间的某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。**一致性:**在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。**隔离性:**数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。**持久性:**事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT *** 作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。*

事务可能出现的问题

    脏读(Dirty Read):
    脏读又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的,值得注意的是,脏读一般是针对于update *** 作的

    不可重复读(Non-repeatable read):

    已知有两个事务A和B,A 多次读取同一数据,B
    在A多次读取的过程中对数据作了修改并提交,导致A多次读取同一数据时,结果不一致.

    幻读(Phantom Read):

    已知有两个事务A和B,A从一个表中读取了数据,然后B在该表中插入了一些新数据,导致A再次读取同一个表,
    就会多出几行,简单地说,一个事务中先后读取一个范围的记录,但每次读取的记录数不同,称之为幻象读。

不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

事务问题的四种解决方案
    **Read uncommitted(读未提交):**可能出现脏读、不可重复读和幻读。Read committed(读提交):可以避免脏读,但可能出现不可重复读和幻读。大多数数据库默认级别就是Read committed,比如Sql Server数据库和Oracle数据库。注意:该隔离级别在写数据时只会锁住相应的行。Repeatable read(重复读):可以避免脏读和不可重复读,但可能出现幻读。注意:①、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key锁;②、如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。Serializable(序列化):可以避免脏读、不可重复读和幻读,但是并发性极低,一般很少使用。注意:该隔离级别在读写数据时会锁住整张表。

Oracle只提供Read commited 和Serializable 和自定义的Read only 级别,Mysql支持四种

事务控制语句:

BEGIN 或 START TRANSACTION 显式地开启一个事务;COMMIT 也可以使用 COMMIT WORK,不过二者是等价的。COMMIT 会提交事务,并使已对数据库进行的所有修改成为永久性的;ROLLBACK 也可以使用 ROLLBACK WORK,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;SAVEPOINT identifier,SAVEPOINT 允许在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT;RELEASE SAVEPOINT identifier 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;ROLLBACK TO identifier 把事务回滚到标记点;SET TRANSACTION 用来设置事务的隔离级别。InnoDB 存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。 MYSQL 事务处理主要有两种方法:

1、用 BEGIN, ROLLBACK, COMMIT来实现

BEGIN 开始一个事务ROLLBACK 事务回滚COMMIT 事务确认

2、直接用 SET 来改变 MySQL 的自动提交模式:

SET AUTOCOMMIT=0 禁止自动提交SET AUTOCOMMIT=1 开启自动提交 二、InnoDB锁

InnoDB隔离级别默认为(Repeatable Read)由于Innodb锁的特性,是解决了幻读的问题的。

行锁(共享锁与排它锁)

行锁也分为共享锁与排它锁。InnoDB的行锁是通过给索引上的==索引项加锁来实现的。只有通过索引条件进行数据检索InnoDB才使用行级锁,否则InnoDB将使用表锁(锁住索引的所有记录)==。

共享锁(Share Lock)

共享锁又称为读锁,是读取 *** 作创建的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排它锁。获得共享锁的事务只能读数据,不能修改数据。

**用途:**主要是用来确认记录是否存在,并确保没有人对这个记录进行是修改,如果当前食物需要对该记录进行修改则需要使用select ... for update获取排它锁,否则容易造成死循环!

语法:selcet ... lock in share mode

排它锁(exclusive lock)

排它锁又称为写锁,简称X锁,排它锁不能与其他锁并存,如一个事务获取了一个数据行的排它锁,其他事务就不能再获取该行的锁(共享锁、排它锁),只有该获取了排它锁的食物是可以对数据行进行读取和修改(其他事务要读取数据可来自快照)

语法:select ... for update(update,delete,insert自动加了排它锁)

为了运行表锁与行锁共同存在,实现多粒度机制,InnoDB还有两种内部使用的意向锁

意向锁-表锁机别

意向锁属于表锁级别。InnoDB自动加的,不需要用户干预。

意向共享锁(IS)意向排它锁(IX)事务打算给数据行加行共享锁,必须先取得该表的IS锁,意向共享锁之间是可以相互兼容的事务打算给数据行加行排他锁,必须先取得该表的IX锁,意向排它锁之间是可以相互兼容的

**意义:**当事务想去进行锁表时,可以先判断意向锁是否存在,存在时则可快速返回该表不能启用表锁。说白了就是这张表如果存在已经被行锁锁住了,就不能加表锁了。

表锁

InnoDB的行锁是通过给索引上的索引项加锁来实现的。只有通过索引条件进行数据检索InnoDB才使用行级锁,否则InnoDB将使用表锁(锁住索引的所有记录)。

也可以通过命令加锁 lock tables xx read/write;(和MyISAM设置表锁一样)

自增锁

针对自增列自增长的一个特殊的表级别锁,当当前的id自增后,但是在事务回滚后,这个id已经被使用过了,就会在表中出现id中间消失的状态。
可以通过 命令查询 show variables like 'innodb_autoinc_lock_mode';
默认取值1 ,代表连续,事务未提交ID

InnoDB锁的实现方式 Next-key Lock 临键锁,InooDB行锁默认算法

当sql执行按照索引进行数据的检索时,查询条件为范围查找(between and、<、>等)并有数据命中则此时SQL语句加上的锁为Next-key locks, 锁住索引的记录+区间。否则就是表锁哦。

临键锁也是解决了RR(Repeatable read)可重复读幻读的问题,原因是当前事务在这个区间做了查询就把当前区间给锁住了,其他事务就不能插入数据,也就不会出现幻读的情况了。

Gap Lock 间隙锁

当查询的记录不存在,临键锁就会退化为间隙锁。

Record Lock 记录锁

总结:

    更新丢失:通过对当前修改线程加排他锁,其他线程就无法修改当前记录;

    脏读:通过对修改记录的事务线程 加排他锁实现,当前线程加了排他锁,其他线程就不能查询当前的记录;

    不可重复读:多次查询的事务线程,对这个线程加上共享锁,这样其他线程想修改这条记录是无法修改的;

    幻读:通过加上Next-key锁,对于多次查询的线程有了临检索就不会让新的数据插入到这个区间来。

死锁

多个并发事务

每个事务都持有锁(或已经在等待锁)

每个事务都需要再继续持有锁

事务之间产生加锁的循环等待,形成死锁

避免死锁
    类似的业务逻辑以固定的顺序访问表和行(重点考虑)大事务拆成小事务同一个事务中,尽可能做到一次锁定锁需要的所有资源,减少死锁概率。如果业务允许,降低隔离级别为表添加合理的索引。如果不走索引会上升为表锁。
三、MVCC多版本并发控制

**MVCC解释:**并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理。以达到用来避免写 *** 作的堵塞,从而引发读 *** 作的并发问题。(没有加锁的读-快照读)

InnoDB存储引擎在每行记录上存有三个默认字段:DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID;

DB_TRX_ID:记录创建的版本号DB_ROLL_PTR:记录回滚的版本号DB_ROW_ID:行自增的id

InnoDB在每行数据都增加三个隐藏字段,一个唯一行号,一个记录创建的版本号,一个记录回滚的版本号。

在多版本并发控制中,为了保证数据 *** 作在多线程过程中,保证事务隔离的机制,降低锁竞争的压力,保证较高的并发量。在每开启一个事务时,会生成一个事务的版本号,被 *** 作的数据会生成一条新的数据行(临时),但是在提交前对其他事务是不可见的,对于数据的更新(包括增删改) *** 作成功,会将这个版本号更新到数据的行中,事务提交成功,将新的版本号更新到此数据行中,这样保证了每个事务 *** 作的数据,都是互不影响的,也不存在锁的问题。

    MVCC插入流程
    添加记录,设置DB_TRX_ID为当前事务ID,DB_ROLL_PTR为NULLMVCC删除流程
    将需要删除的记录的DB_ROLL_PTR设置为当前事务IDMVCC更新流程
    将原记录的DB_ROLL_PTR设置为当前事务ID,复制原记录生成新记录(此时同MVCC插入流程)MVCC查询流程
      查询的数据行的DB_TRX_ID版本ID要小于当前事务ID查找数据行的DB_ROLL_PTR为NULL或大于当前事务版本号的记录,后面的事务删除的数据还未提交的仍可以找到。
四、Undo log

undo 意为取消,以撤销 *** 作为目的,返回指定某个状态的 *** 作

undo log 指事务开始之前,在 *** 作任何数据之前,首先将需 *** 作的 数据备份到一个地方(Undo Log)

Undo Log 是为了实现事务的原子性而产物

事务处理过程中 如果出现了错误或者用户执行了 ROLLBACK 语句,Mysql 可以利用Undo Log 中的备份将数据恢复到事务开始之前的状态。

UndoLog 在Mysql innodb 存储引擎中用来实现多版本并发控制

事务未提交之前,Undo 保存了未提交之前的版本数据,Undo中的数据可作为数据旧版本快照供其他并发事务进行快照读

快照读:
SQL 读取的 数据 是快照版本,也就是历史版本 , 普通的SELECT 就是快照读;innodb 快照读,数据的读取将由 cache( 原本数据) + undo( 事务修改前的数据) 两部分组成(即前面的MVCC和undo log组成)

当前读:
SQL 读取的 数据 是最新版本 。通过锁机制来保证读取的数据无法通过其他事务进行修改;UPDATE 、DELETE 、INSERT 、SELECT … LOCK IN SHARE MODE 、SELECT … FOR UPDATE 都是当前读。

五、Redo log Redo Log 概念:
    Redo ,顾名思义就 是 重做。以恢复 *** 作为目的,重现 *** 作 ;Redo log 指事务中 *** 作 的 任何数据,将最新的 数据备份到一个地方 (Redo Log)
持久性

RedoLog 是为了实现事务的持久性而出现的产物

防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql 服务的时候,根据redo log 进行重做,从而达到事务的 未入磁盘数据进行持久化这一特性。

配置

(Redo Log)

持久性

RedoLog 是为了实现事务的持久性而出现的产物

防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql 服务的时候,根据redo log 进行重做,从而达到事务的 未入磁盘数据进行持久化这一特性。

[外链图片转存中…(img-HmGEAYez-1643468934975)]

配置

OS cache指的是系统级别的。

本文参考的博客链接

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/zaji/5719549.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存