前言

接上文,继续学习后续章节。细心的同学已经发现,我整理的并不一定是作者讲的内容,更多是结合自己的理解,加以阐述,所以建议结合原文一起理解。

第20章《幻读是什么,幻读有什么问题?》

先看下幻读的定义:

在一个事务中,两次执行同一个查询SQL,后一次执行结果比前一次执行结果数量变多了,称之为幻读。

在隔离级别中的定义,我们知道RR级别是无法避免幻读的?但是在innoDB中是如果做到避免幻读问题呢?其实innoDB在RR级别下解决幻读问题也并不完美。

现有一张表t,有三个字段 id主键,普通索引C,不带索引d, 目前有数据id=1,d=5,c=5;id=4,d=5,c=5;

事务A 事务B 事务C
begin;
select * from t where d =5 for update;Q1
update t set d =5 where id =4;
select * from t where d =5 for update;Q2
insert into t values (5,5,5)
select * from t where d =5 for update;Q3
commit;

首先我们知道innoDB在RR级别下,select语句是快照读,不存在幻读问题,快照读的实现方式我们之前阐述过,通过MCVV多版本并发控制解决的,本质就是通过undo log实现的,如果还需要更详细的研究,可以参考《一文讲透MVCC原理》

Q2读到事务B的更新预警,属于当前读看到的,不属于幻读.幻读指的是新插入的行。

首先我们看下,幻读不解决可能会出现哪些问题?

1、首先如果只加行锁,执行Q1时,我们希望的是所有d=5的数据都锁定,但d=5的是id=1的数据,只会对id=1加上行锁.当事务B执行时,是对id=4进行更新操作,所以可以操作.同样的事务C也可以执行,那么就违背了,Q1的语义.

2、数据一致性问题:如果事务A在Q1时候又执行了一个按d=5条件更新语句,那么在所有事务都提交后,落入到binlog中的顺序是,事务B更新一个语句把id=4的d改成了5,事务C插入了一个id=5,d=5的数据,事务A执行了一个把d=5的数据更新。此时如果按binlog的执行顺序,则会把事务B事务C的逻辑全部改掉,造成了数据不一致的问题。

所以innoDB为了解决此类幻读问题,就引入了间隙锁(Gap lock);

顾名思义就是在行与行之间也加上锁.

比如上面例子中,有id=1和id=4两个数据,那么我不仅在行上加锁,我再(- ∞ ,1](1,4],(4, + supremum】上也加上锁,那么当你再插入数据的时候,就无缝可入了就会被阻塞住。

但需要注意的是,在行锁中,读写锁,写写锁互相冲突,当一个事务加间隙锁,另外一个事务也可以对同样的范围加间隙锁。

注意:

当我们执行更新加间隙锁时,如果where条件不是索引,那么就会对所有行加行锁和行之间数值范围加间隙锁。

如果执行的where条件是等值并且是非唯一索引列,比如id=5,那么会对id=5加行锁,以及(id=5上一个id,id=5]和(id=5,id=5的下一个id值]加间隙锁。如果是唯一索引,那么就只加行锁。

第21章《为什么只改一行代码,锁这么多》

这章节,老师总结的加锁规则,非常受用:两个原则,两个优化,一个BUG

两个原则:

1、加锁的基本单位是以next-key lock。就是左开右闭。

2、查找过程中访问的到对象才会加锁。

两个优化:

1、在索引上等值查询条件,如果是唯一索引,会优化成行锁。

2、在索引上等值查询条件,会向右遍历找到第一个不符合条件的为止,并会优化成间隙锁。

一个bug:

在唯一索引上的范围查询,会访问到不满足条件为止。

带着这些规则,下面看八个案例,以表T为背景,来实践下。

CREATE TABLE`t`(
`id`int(11)NOT NULL,
`c`int(11)DEFAULT NULL,
`d`int(11)DEFAULT NULL,
PRIMARY KEY(`id`),
KEY`c`(`c`)
) ENGINE=InnoDB; insert intot values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);

案例一:等值查询的情况

update t set d=d+1 where id =7;

根据主键id进行更新时,由于id=7不存在。根据规则1加锁单位next-key lock :(5,10] 根据优化2: 退化成间隙锁(5,10);

此时分别执行两个SQL:

insert into t values(8,8,8) --由于间隙锁,会block
update t set d=d+1 where id =10; --不在间隙锁范围内,执行成功

经过实验,证实如此。

案例二:非唯一索引等值查询

begin;
select id from t where c=5 lock in share mode;

根据优化2 可知会在索引C间隙锁 (5,10);

但需要注意的是:根据规则2 只有访问到的对象才会加锁,由于使用了覆盖索引,所以不会再主键id上再加锁。

update t set d=d+1 where id =5; --执行不受阻
insert into t values(7,7,7); --blocked

案例三:主键索引范围查询

select * from t where id =10 for update;
select * from t where id>=10 and id <11;

首先从结果上看,这两个SQL执行结果是一样的,但是按照上面总结的加锁规则,加锁过程是不一样的。

SQL1 唯一索引等值查询,则加的是id=10的行锁。

SQL2 首先会查询到id=10这行,加锁单位next-key lock,(5,10],根据优化1,退化成行锁,只加id=10这一行,

再查询id>10,向右找到第一个不满足条件的行id=15,加next-key lock (10,15]

案例四:非唯一索引范围锁

select * from t where c>= 10 and c<11 for update;

首先找到c=10这一行,加next-key (5,10],再根据优化2,向右查询到第一个不满足条件的值,退还成间隙锁(10,15]

案例五:唯一索引范围锁bug

select * from t where id>10 and id<=15 for update;

正常id是唯一索引,找到id=15这时 ,应该就停止扫描了,但是innoDB会依然扫描到第一个不满足条件的id=20为止。

所以就会加(10,15],(15,20],导致id=20这样也会锁上,这是没有必要的。这个bug已被官方证实,但还未修复。

案例六:未唯一索引存在多个相同值的情况

--先插入一条c=10的值,这样表中存在2个c=10的行
insert into t values(30,10,30);

当我们在c=10加锁时,加锁的范围是next-key lock (5,10] next-key lock (10,10]和间隙锁 (10,15)

案例七:limit 语句加锁

delete from t where c =10 limit2;

与案例7的加锁范围不同的时,不会再加间隙锁(10,15);

因为当扫描到c=10,id=30这一行时,已经满足limit2的条件,不会再往后扫描,也就不会再加间隙锁(10,15),从而缩小了锁的范围。

所以在删除数据的时候,我们尽量加limit ,即可以控制删除数量,又可以缩小锁的范围。

案例八:一个说死锁的例子

A执行第一句SQL时,按加锁规则,会加next-key lock (5,10]和间隙锁(10,15)。

B执行时,也会加next-key lock(5,10],会被阻塞.

A再次执行插入数据(8,8,8)时,也会被阻塞,从而导致死锁。

这是为什么了?B 不是没有加锁成功吗?但是我们要注意的时,加next-key lock 本质就是加间隙锁再加行锁。由于间隙锁加之间不是互斥的,所以B加(5,10)的间隙锁时成功了,加c=10的行锁失败。

所以当A再次插入数据时,已被间隙锁阻塞。

第23章《MySQL怎么保证数据不丢失的?》

binlog写入机制

事务执行时,先把日志写到binlog cache,事务提交后再把binlog cache 写入binlog文件。

binlog_cache_size控制了每个线程的binlog cache的内存的大小。如果超过了这个参数就临时存到磁盘中。

但注意的是,binlog cache并不一定是直接落入磁盘的,是先写入binlog files,再刷入磁盘。

这个可以通过参数sync_binlog控制:

设置0,表示每次只写入binlog files,不刷磁盘

设置1,表示每次事务提交,也会刷磁盘

设置n,表示每次都写入binlog files,但是等累计了n个事务才刷磁盘

常见设置为"100-1000",但同时也会有丢失的风险.

redo log写入机制

事务执行时,先把日志写入 redo log buffer,事务提交时,写入文件系统page cache 或者刷入磁盘.也是通过参数来设置:innoDB_flush_log_at_trx_commit

设置0,表示每次事务提交时,依然保留在redo log buffer

设置1,表示每次事务提交直接刷入磁盘

设置2,表示每次事务提交都只写到page cache.

那是不是0,2状态是不是就永不刷到磁盘了,那不是会有丢失的风险吗?

其实不是的,innoDB有一个后台线程,每隔1秒,会把redo log buffer中的日志,写到page cache,然后再调用fsync刷到磁盘.

由于这个后台线程的存在,所以也会把还未提交事务的redo log 也持久化到磁盘.

如果你的如果你的MySQLMySQL现在出现了性能瓶颈,而且瓶颈在现在出现了性能瓶颈,而且瓶颈在IO上,可以通过哪些方法来提升性能呢?上,可以通过哪些方法来提升性能呢?

针对这个问题,可以考虑以下三种方法:

1.设置binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count参数,减少binlog的写盘次数。这个方法是基于“额外的故意等待”来实现的,因此可能会增加语句的响应时间,但没有丢失数据的风险。

2.将sync_binlog设置为大于1的值(比较常见是100~1000)。这样做的风险是,主机掉电时会丢binlog日志。

3.将innodb_flush_log_at_trx_commit设置为2。这样做的风险是,主机掉电的时候会丢数据。

MySQL深入研究--学习总结(5)的更多相关文章

  1. MySQL深入研究--学习总结(2)

    前言 接上文,继续学习后续章节. 第四章&第五章<深入浅出索引> 这两章节主要介绍的索引结构及其如何合理建立索引,但是我觉得讲的比较简单. 总结回顾下吧,其实在我之前的文章< ...

  2. MySQL深入研究--学习总结(1)

    前言 本文是笔者学习"林晓斌"老师的<MySQL实战45讲>过程中的,对知识点的总结归纳以及对问题的思考记录,课程18年11月就出了,当时连载形式,我就上班途中一边开车 ...

  3. MySQL深入研究--学习总结(3)

    前言 接上文,继续学习后续章节.细心的同学已经发现,我整理的并不一定是作者讲的内容,更多是结合自己的理解,加以阐述,所以建议结合原文一起理解. 第九章<普通索引和唯一索引,如何选择> 从查 ...

  4. MySQL深入研究--学习总结(4)

    前言 接上文,继续学习后续章节.细心的同学已经发现,我整理的并不一定是作者讲的内容,更多是结合自己的理解,加以阐述,所以建议结合原文一起理解. 第13章<为什么表数据删除一般,表文件大小不变?& ...

  5. 【转】手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)

    1.引言 特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途.如本文内容有不妥之处,请联系JackJiang进行处理!   我司有关部门为了获取黑产群的动态,有同事潜伏在大量的黑产群 ...

  6. 手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)

    1.引言 特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途.如本文内容有不妥之处,请联系JackJiang进行处理!   我司有关部门为了获取黑产群的动态,有同事潜伏在大量的黑产群 ...

  7. 13本热门书籍免费送!(Python、SpingBoot、Entity Framework、Ionic、MySQL、深度学习、小程序开发等)

    七月第一周,网易云社区联合清华大学出版社为大家送出13本数据分析以及移动开发的书籍(Python.SpingBoot.Entity Framework.Ionic.MySQL.深度学习.小程序开发等) ...

  8. MySQL 定时器EVENT学习

    原文:http://blog.csdn.net/lifuxiangcaohui/article/details/6583535 MySQL 定时器EVENT学习 MySQL从5.1开始支持event功 ...

  9. 《Mysql 公司职员学习篇》 第二章 小A的惊喜

          第二章 小A的惊喜  ---- 认识数据库 吃完饭后,小Y和小A回到了家里,并打开电脑开始学习Mysql. 小Y:"小A,你平时的Excell文件很多的情况下,怎么样存放Exce ...

随机推荐

  1. Please commit your changes or stash them before you merge问题解决

    问题描述 error: Your local changes to the following files would be overwritten by merge: xxx/xxx/xxx.c P ...

  2. 016.NET5_MVC_视图组件扩展定制

    视图组件 1. 呈现页面响应的某一部分而不是整个响应 2. 包括在控制器和视图之间发生的关注分类和可测试优势 3.可以具有参数和业务逻辑 4. 通常在页面局部调用 如何自定义视图组件? 1.Razor ...

  3. go modules——HelloWorld示例

    go modules--HelloWorld示例 go modules 存在的意义是方便代码的共享(虽然这会使自己开发过程中有一些小小的麻烦) 开发第一步,创建一个github仓库,然后克隆到本地 首 ...

  4. SVG 与 Canvas 对比

    SVG 与 Canvas 对比 技术选型 SVG vs Canvas 应用场景 性能 GPU 加速 XML 数据存储 Canvas 2D Canvas 3D WebGL / OpenGL ES thr ...

  5. javascript change array length methods

    javascript change array length methods Array 改变数组长度的方法 push, pop shift, unshift, splice, fill, 不改变数组 ...

  6. flutter 插件调用callback函数

    dart plugin class TestLib { static MethodChannel _channel = const MethodChannel('test_lib') ..setMet ...

  7. RT-Thread学习笔记3-线程间通信 & 定时器

    目录 1. 事件集的使用 1.1 事件集控制块 1.2 事件集操作 2. 邮箱的使用 2.1 邮箱控制块 2.2 邮箱的操作 3. 消息队列 3.1 消息队列控制块 3.2 消息队列的操作 4. 软件 ...

  8. 星空值、SPC、算力组成三元永动机制!VAST带你把握时代!

    目前中心化金融体系为用户提供的服务在便捷性和易用性方面已经达到了新高度,但随着时代发展,大众对于金融安全性和可控性的需求进一步提升,需要去中心化金融服务商来提供更具创意的解决方案.盛大公链为此在应用层 ...

  9. NGK英国路演圆满结束,未来科技布局看好NGK公链技术

    近日,NGK全球路演英国站在首都伦敦圆满结束.区块链业内专家.各投行精英.各市场节点代表.八大产业代表参加了此次路演.同时,英国经济学人.每日邮报.金融时报等近百家财经媒体对此路演进行了大力报道.并且 ...

  10. Baccarat如何点燃DEFI市场?

    目前DeFi是成为了各大生态的"兵家必争之地",与此同时DeFi的高收益也成为吸引散户入局的一个利器.而虽然流动性挖矿板块近期的温度有所下降,但是这其中不乏还是有很多收益颇丰的De ...