mysql事务ACID原理MVCC 幻读

文章目录

    • mysql事务原理MVCC
    • 1存储引擎
      • 1.InnoDB存储引擎
      • 2.MyISAM存储引擎
    • 2.undo和redo的功能
      • undo:
      • redo:
    • 3.mysql锁
      • 3.1表级锁
      • 3.2行级锁
      • 3.3全局锁
      • 3.4避免阻塞与死锁
        • 阻塞:食堂排队
      • 3.5.mysql死锁
        • 不同表
        • 同一个表
        • 避免死锁
    • 4.MVCC多版本并发控制
      • mvcc如何解决隔离性
      • 隐式字段
      • Read View
      • 读已提交RC read-commited
      • 解决不可重复读RR read-repeatable
      • 解决不了幻读
    • 5.总结

mysql事务原理MVCC

书籍推荐:mysql必知必会

​ 深入浅出mysql

​ mysql高性能(偏DBA)

数据量较小:索引(一个库)

数据量较大:分库分表,读写分离

mysql优化是一个大的范围,需要丰富的经验,课程中会把作为一个java程序员(非DBA)基本的、常用的一一列举出来,希望大家尽可能多的掌握,因为太多了,而我们重点在java,所以每个知识点都只会抽取重点来学习。如果以后大家项目中需要这方面的,大家以这个为基础,再去深入学习,也是没有问题的。

select * from xxx where id=1

mysql事务ACID原理MVCC 幻读_第1张图片

①建立连接1.1(Connectors&Connection Pool),通过客户端/服务器通信协议与MySQL建立连
接。MySQL 客户端与服务端的通信方式是 “ 半双工 ”。对于每一个 MySQL 的连接,时刻都有一个
线程状态来标识这个连接正在做什么。
通讯机制:
全双工:能同时发送和接收数据,例如平时打电话。
半双工:指的某一时刻,要么发送数据,要么接收数据,不能同时。例如早期对讲机
单工:只能发送数据或只能接收数据。例如单行道
线程状态:系统故障

show processlist; //查看用户正在运行的线程信息,root用户能查看所有线程,其他用户只能看自
己的
id:线程ID,可以使用kill xx;
user:启动这个线程的用户
Host:发送请求的客户端的IP和端口号
db:当前命令在哪个库执行
Command:该线程正在执行的操作命令
Create DB:正在创建库操作
Drop DB:正在删除库操作
Execute:正在执行一个PreparedStatement
Close Stmt:正在关闭一个PreparedStatement
Query:正在执行一个语句
Sleep:正在等待客户端发送语句
Quit:正在退出
Shutdown:正在关闭服务器
Time:表示该线程处于当前状态的时间,单位是秒
State:线程状态
Updating:正在搜索匹配记录,进行修改
Sleeping:正在等待客户端发送新请求
Starting:正在执行请求处理
Checking table:正在检查数据表
Closing table : 正在将表中数据刷新到磁盘中
Locked:被其他查询锁住了记录
Sending Data:正在处理Select查询,同时将结果发送给客户端
Info:一般记录线程执行的语句,默认显示前100个字符。想查看完整的使用show full
processlist;

②查询缓存(Cache&Buffer),这是MySQL的一个可优化查询的地方,如果开启了查询缓存且在
查询缓存过程中查询到完全相同的SQL语句,则将查询结果直接返回给客户端;如果没有开启查询
缓存或者没有查询到完全相同的 SQL 语句则会由解析器进行语法语义解析,并生成“解析树”。

缓存Select查询的结果和SQL语句
执行Select查询时,先查询缓存,判断是否存在可用的记录集,要求是否完全相同(包括参
数值),这样才会匹配缓存数据命中。
即使开启查询缓存,以下SQL也不能缓存
查询语句使用SQL_NO_CACHE
查询的结果大于query_cache_limit设置
查询中有一些不确定的参数,比如now()
show variables like '%query_cache%'; //查看查询缓存是否启用,空间大小,限制等
show status like 'Qcache%'; //查看更详细的缓存参数,可用缓存空间,缓存块,缓存多少等

③解析器(Parser)将客户端发送的SQL进行语法解析,生成"解析树"。预处理器根据一些MySQL
规则进一步检查“解析树”是否合法,例如这里将检查数据表和数据列是否存在,还会解析名字和别
名,看看它们是否有歧义,最后生成新的“解析树”。

查询优化器(Optimizer)根据“解析树”生成最优的执行计划。MySQL使用很多优化策略生成最
优的执行计划,可以分为两类:静态优化(编译时优化)、动态优化(运行时优化)。

等价变换策略
A:5=5 and a>5 改成 a > 5 去除恒成立条件
a < b and a=5 改成b>5 and a=5
基于联合索引,调整条件位置等
优化count、min、max等函数
InnoDB引擎min函数只需要找索引最左边
InnoDB引擎max函数只需要找索引最右边
MyISAM引擎count(*),不需要计算,直接返回
提前终止查询
使用了limit查询,获取limit所需的数据,就不在继续遍历后面数据
in的优化
MySQL对in查询,会先进行排序,再采用二分法查找数据。比如where id in (2,1,3),变
成 in (1,2,3) 

B:join优化:inner join/join 自动优化小表驱动大表,left right没法优化
select from a join b  10万个  20万--40万
select from b join a  1000个  2000-4000   
a表大,b表小,基于主键索引,每条数据查询的IO次数2-4

⑤查询执行引擎负责执行 SQL 语句,此时查询执行引擎会根据 SQL 语句中表的存储引擎类型,以
及对应的API接口与底层存储引擎缓存或者物理文件的交互,得到查询结果并返回给客户端。若开
启用查询缓存,这时会将SQL 语句和结果完整地保存到查询缓存(Cache&Buffer)中,以后若有
相同的 SQL 语句执行则直接返回结果。
如果开启了查询缓存,先将查询结果做缓存操作
返回结果过多,采用增量模式返回

1存储引擎

存储引擎:

MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能。

这些不同的技术以及配套的相关功能在 MySQL中被称作存储引擎(也称作表类型)

因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(Table Type,即存储和操作此表的类型)。

Mysql存储引擎分类:

MyISAM、InnoDB、MEMORY、MERGE等

CREATE TABLE `brand` (
  `id` int(11) NOT NULL AUTO_INCREMENT
) ENGINE=InnoDB DEFAULT CHARSET=utf8; #指定引擎

默认存储引擎

SHOW ENGINES

mysql事务ACID原理MVCC 幻读_第2张图片

1.InnoDB存储引擎

InnoDB是事务型数据库的首选引擎,通过上图也看到了,InnoDB是目前MYSQL的默认事务型引擎,是目前最重要、使用最广泛的存储引擎。支持事务安全表(ACID),支持行锁定和外键。InnoDB主要特性有:

1、InnoDB mysql现在默认支持的引擎,每张表的存储都按主键顺序存放,如果没有显示在表定义时指定主键,InnoDB会为每一行生成一个6字节的隐藏ROWID,并以此作为主键

2、支持事务安全表(ACID),支持行锁定和外键

场景:由于其支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。因为支持事务的提交(commit)和回滚(rollback)。

总结:(理解并记住)

1.支持事务、支持外键
2.支持行级锁与表级锁
3.花费资源去处理事务,效率比不上MyISAM
4.有事务日志,恢复数据较方便
5.索引为聚簇索引
	虽然InnoDB不断优化,效率已经有了很大提升,但是还是比不上MyISAM

2.MyISAM存储引擎

MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事物和外键。

总结(记住)

Mysql 5.5版本之前的默认的存储引擎
1.不支持事务、不支持外键
2.只支持表级锁(后面介绍)
3.没有事务日志,故障恢复数据较麻烦
4.分区存放文件,平均分配IO,不用花费资源去处理事务,效率较高
5.索引为非聚簇索引

2.undo和redo的功能

id 1 name 张三

update xxx set name=‘李四’ where id=1

mysql为提高效率,每次修改不会直接修改磁盘,会先修改buffer,然后再由mysql自己的线程purge去刷新到磁盘。为了支持回滚,得记录修改之前得状态

事务开启前,先写undo日志

undo:

保证了事务原子性

数据修改前的内容(用于回滚),当把数据从磁盘读取内存的时候,每次数据操作这些数据都会变脏,就是脏数据,需要都会记录undo日志。当发生回滚的时候,就需要这些日志用来回滚数据

Undo:意为撤销或取消,以撤销操作为目的,返回指定某个状态的操作。
Undo Log:数据库事务开始之前,会将要修改的记录存放到 Undo 日志里,当事务回滚时或者数
据库崩溃时,可以利用 Undo 日志,撤销未提交事务对数据库产生的影响。
Undo Log产生和销毁:Undo Log在事务开始前产生;事务在提交时,并不会立刻删除undo
log,innodb会将该事务对应的undo log放入到删除列表中,后面会通过后台线程purge thread进
行回收处理。Undo Log属于逻辑日志,记录一个变化过程。例如执行一个delete,undolog会记
录一个insert;执行一个update,undolog会记录一个相反的update。
Undo Log存储:undo log采用段的方式管理和记录。在innodb数据文件中包含一种rollback
segment回滚段,内部包含1024个undo log segment。可以通过下面一组参数来控制Undo log存
储。

实现事务的原子性
Undo Log 是为了实现事务的原子性而出现的产物。事务处理过程中,如果出现了错误或者用户执
行了 ROLLBACK 语句,MySQL 可以利用 Undo Log 中的备份将数据恢复到事务开始之前的状态。
实现多版本并发控制(MVCC)
Undo Log 在 MySQL InnoDB 存储引擎中用来实现多版本并发控制。事务未提交之前,Undo Log
保存了未提交之前的版本数据,Undo Log 中的数据可作为数据旧版本快照供其他并发事务进行快
照读
 事务A手动开启事务,执行更新操作,首先会把更新命中的数据备份到 Undo Buffer 中。
 事务B手动开启事务,执行查询操作,会读取 Undo 日志数据返回,进行快照读

undo log是用来回滚数据的用于保障 未提交事务的原子性

redo:

数据修改后的内容,在缓冲池,然后数据修改后生成redo日志,需要把这些内存中的数据插入到磁盘。这个时候当数据库宕机的时候。这些redo就是重要的记录,重启之后会把redo日志也就是修改的数据重新写入数据库。

写buffer得时候,也会同时写redo日志,因为写redo(顺序io)日志的速度远远高于,写mysql数据(mysql数据以页为单位存储,随机io)

保证了ACID的持久性

(1)redo log 的存储是顺序存储,而缓存同步是随机操作。

(2)缓存同步是以数据页为单位的,每次传输的数据大小大于redo log。Redo:顾名思义就是重做。以恢复操作为目的,在数据库发生意外时重现操作。
Redo Log:指事务中修改的任何数据,将最新的数据备份存储的位置(Redo Log),被称为重做
日志。
Redo Log 的生成和释放:随着事务操作的执行,就会生成Redo Log,在事务提交时会将产生
Redo Log写入Log Buffer,并不是随着事务的提交就立刻写入磁盘文件。等事务操作的脏页写入
到磁盘之后,Redo Log 的使命也就完成了,Redo Log占用的空间就可以重用(被覆盖写入)。
Redo Log工作原理
Redo Log 是为了实现事务的持久性而出现的产物。防止在发生故障的时间点,尚有脏页未写入表
的 IBD 文件中,在重启 MySQL 服务的时候,根据 Redo Log 进行重做,从而达到事务的未入磁盘
数据进行持久化这一特性

redo log是用来恢复数据的 用于保障,已提交事务的持久化特性
(1)redo log 的存储是顺序存储,而缓存同步是随机操作。

(2)缓存同步是以数据页为单位的,每次传输的数据大小大于redo log。
假设有A、B两个数据,值分别为1,2.
1. 事务开始
2. 记录A=1到undo log
3. 修改A=3
4. 记录A=3到 redo log
5. 记录B=2到 undo log
6. 修改B=4
7. 记录B=4到redo log
8. 将redo log写入磁盘
9. 事务提交

3.mysql锁

1.增删改,mysql会默认加写锁

2.select * from sing where s_num=‘10001’ lock in share mode;加读锁 读读可以共享

3.读写锁不共享

4.for update 加的写锁

共享锁与排他锁

  • 共享锁(读锁):其他事务可以读,但不能写。

  • 排他锁(写锁) :其他事务不能读取,也不能写。

    MySQL 不同的存储引擎支持不同的锁机制,所有的存储引擎都以自己的方式显现了锁机制,服务器层完全不了解存储引擎中的锁实现:
    
    MyISAM 和 MEMORY 存储引擎采用的是表级锁(table-level locking)
    BDB 存储引擎采用的是页面锁(page-level locking),但也支持表级锁
    InnoDB 存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。
    默认情况下,表锁和行锁都是自动获得的, 不需要额外的命令。
    
    但是在有的情况下, 用户需要明确地进行锁表或者进行事务的控制, 以便确保整个事务的完整性,这样就需要使用事务控制和锁定语句来完成。
    

    3.1表级锁

    锁住整张表,开销小,加锁快;不会出现死锁(因为MyISAM会一次性获得SQL所需的全部锁);锁定粒度大,发生锁冲突的概率最高,并发度最低。 演示:两个cmd

    lock table xxxx write/read

    unlock tables

mysql事务ACID原理MVCC 幻读_第3张图片

3.2行级锁

开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高

select xxx for update

mysql事务ACID原理MVCC 幻读_第4张图片

3.3全局锁

全局锁就是对整个数据库实例加锁。MySQL提供了一个加全局读锁的方法,命令是Flush tables with read lock。当需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句

全局锁的典型使用场景是,做全库逻辑备份。也就是把整库每个表都select出来存成文本

但是让整个库都只读,可能出现以下问题:

  • 如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆
  • 如果在从库上备份,那么在备份期间从库不能执行主库同步过来的binlog,会导致主从延迟

3.4避免阻塞与死锁

阻塞:食堂排队

1.详细的分析产品需求 会有哪些查询,哪些修改,好好建表,减少长事务操作

2.分布式事务中,采用弱一致性,可以减少阻塞

3.最直接最简单的方法就是把表的数据量变小(针对于数据量确实很大了,分库分表)

4.当然sql语句调优、提高代码质量等都是很重要的

如果真的出现了:

show full PROCESSLIST:查看状态,可以参考前面的属性,必要情况下 直接kill

3.5.mysql死锁

相互等待对方释放锁,形成死锁

不同表

mysql事务ACID原理MVCC 幻读_第5张图片

同一个表

mysql事务ACID原理MVCC 幻读_第6张图片

避免死锁

1.编号解死锁:对锁编号,按顺序锁。 比如AB 每个线程都做判断,始终先锁A 在锁B

2.首先在innodb搜索引擎中,会根据算法主动进行部分死锁的检测与释放,比如上面的例子自动释放。

3.大事务拆小。大事务更倾向于死锁,大事务锁的时间长,如果业务允许,将大事务拆小(DBA建表功底)。

4.为表添加合理的索引

4.MVCC多版本并发控制

最主要就是解决读写互斥,写时复制读写分离,空间换时间

id :1 name 张三

事务1:select * from xxx where id=1 ------>复制在一个地方

事务2:update xxx where id=1 数据库改

改的地方跟我读的不是同一个,读写分离

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

在学习MVCC多版本并发控制之前,我们必须先了解一下,什么是MySQL InnoDB下的当前读和快照读?

  • 当前读
    像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

    A事务:select * from xxxx in share mode 当前读,读取到数据库最新数据

    ​ 一系列操作…

    ​ select * from xxxx in share mode 当前读,读取到数据库最新数据

    ​ 因为加锁,如果没有锁,使用当前读,就会出现不可重复读,幻读

  • 快照读
    像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本

    A事务:select * from xxxx 把当前这个时刻的记录照个相,在内存中就是复制了一份数据

    ​ 一系列操作。。。。操作的过程中有可能其它事务已经更改了数据

    ​ select * from xxxx 这次读取不会读到其它事务修改数据,因为在一个事务中如果没有触发当前读,那 么就只会有一次快照读

    ​ 所以mvcc的快照读就在不加锁的锁 的情况下解决了不可重复读,既然没有加锁,那么这边查询,其它事务就可以更改,于是解决读写冲突

数据库并发场景有三种,分别为:(针对没有措施的情况下)

  • 读-读:不存在任何问题,也不需要并发控制

  • 读-写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读

  • 写-写:有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失

第一类更新丢失:

A事务撤销了B事务操作
mysql事务ACID原理MVCC 幻读_第7张图片

第二类更新丢失

A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失

mysql事务ACID原理MVCC 幻读_第8张图片

mvcc如何解决隔离性

隐式字段

每行记录除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段

id: 1 name zhangsan 事务id:1

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

  • DB_ROLL_PTR
    7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里)undo日志记录了很多操作

    当前的这条数据,得找到对应得日志,靠指针

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

  • 实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了

mysql事务ACID原理MVCC 幻读_第9张图片

undo日志只是记录得事务操作得反向操作.

A事务正在执行,把buffer age改成25,但是没有提交

B事务来读取数据,应该读取24,24哪儿来呢

Read View

什么是Read View,说白了Read View就是事务进行快照读操作的时候生产的读视图

mysql事务ACID原理MVCC 幻读_第10张图片

当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以最新的事务,ID值越大

Read View简单的理解成有三个全局属性:

trx_list
一个数值列表,用来维护Read View生成时刻系统正活跃的事务ID  
例如:
我自己的事务时事务2
1操作未提交 3操作未提交 4已经提交  放入trx_list:[1,3]
low_limit_id
记录trx_list列表中事务ID最小的ID   就是1
next_limit_id
ReadView生成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1
5

1.如果当前buffer里面的事务id x小于trx_list里面的最小id(low_limit_id) 可以读取这个事务id x的数据
事务2开启,事务3开启,我是事务4,事务5 ,  事务id是自增的 buffer的顺序应该1-2-3-4-5,那个事务最近操作了我,事务id就是谁
事务4开启事务,生成快照读,读取到buffer中当前字段的隐藏事务id是1. 因为事务1的操作一定在2345前面,所以事务id能为1一定是事务1回滚或者提交了
第一条满足就不会走后面
2.如果第一条没有满足,比较读取到buffer中的事务id,比next_limit_id还大,不可读取,我生成快照的时候最大值就是5,你比5还大说明生成快照的时候压根没有开启这个事务,肯定不能读取。
3.2条满足的情况下,把在buffer中读取到的事务id,去trx_list里面遍历,如果trx_list里面有说明还在活跃,不能读取,否则可以读取

因为这三条,使用mvcc 乐观锁来保证并发隔离性,并没有加锁

mysql事务ACID原理MVCC 幻读_第11张图片

读已提交RC read-commited

会出现不可重复读

A事务: 第一次select 生成快照

​ 第二次select 又会生成快照

​ 每一次都会生成快照

会不会脏读?不会,因为上面的mvcc条件判断

会不会不可重复读呢?会出现, 比如上面的例子,第一次4提交,3没有提交。buffer中的事务id是4 根据条件4满足直接读取。如果第二次快照3提交了,buffer中事务id是3,根据地址。直接定位3的版本链.两次的结果不一致

readview会改变

解决不可重复读RR read-repeatable

只是多次读取,只会有一次快照

A事务: 第一次select 生成快照

​ 第二次select 不会生成

肯定避免了不可重复读

A事务第一次读取了,另外一个事务修改了,A事务再次读取数据一致

解决不了幻读

如果只是多次读取是可以解决幻读的,因为不会出现当前读,只会生成一次快照。

1.a事务先select(触发快照生成),b事务insert确实会加一个gap锁,但是如果b事务commit,这个gap锁就会释放(释放后a事务可以随意操作), student表9条数据,生成快照,b事务插入/删除了一条数据,并且提交

2.a事务再select出来的结果在MVCC下还和第一次select一样,不会幻读,生成了一次快照了不会再次生成,没有幻读

3.接着a事务不加条件地update,这个update会作用在所有行上(包括b事务新加的),

​ update 需要更新全表

​ 增删改触发锁,触发当前读,需要读取最新的数据,读取到10条

4.a事务再次select就会出现b事务中的新行,并且这个新行已经被update修改了. 刚才的快照读已经丢失了,因为在中间有一次当前读

上面这样,事务2提交之后,事务1再次执行update,因为这个是当前读,他会读取最新的数据,包括别的事务已经提交的,所以就会导致此时前后读取的数据不一致,出现幻读。

mysql事务ACID原理MVCC 幻读_第12张图片

InnoDB有三种行锁的算法:

尽量弥补错误。

1,Record Lock:单个行记录上的锁。

2,Gap Lock:间隙锁,锁定一个范围,但不包括记录本身。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。

3,Next-Key Lock:1+2,锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题

mysql事务ACID原理MVCC 幻读_第13张图片

超时时间的参数:innodb_lock_wait_timeout ,默认是50秒。
超时是否回滚参数:innodb_rollback_on_timeout 默认是OFF。

默认情况下,InnoDB存储引擎不会回滚超时引发的异常,除死锁外。

因为InnoDB对于行的查询都是采用了Next-Key Lock的算法,锁定的不是单个值,而是一个范围,按照这个方法是会和第一次测试结果一样。但是,当查询的索引含有唯一属性的时候,Next-Key Lock 会进行优化,将其降级为Record Lock,即仅锁住索引本身,不是范围。

注意:通过主键或则唯一索引来锁定不存在的值,也会产生GAP锁定

如何让测试一不阻塞?可以显式的关闭Gap Lock:

1:把事务隔离级别改成:Read Committed,提交读、不可重复读。SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

2:修改参数:innodb_locks_unsafe_for_binlog 设置为1。

mvcc+间隙锁:完成了事务隔离性但是依然没有彻底解决幻读吧

5.总结

对ACID的回答要提高,幻读,不可重复读

undo日志:保证原子性

redo日志:保证持久性

mvcc+锁:保证隔离性

原子性+持久性+隔离性=一致性(最终目的)

你可能感兴趣的:(MySQL,数据库,mysql)