MySQL中的锁、隔离等级和读场景
一、导言
关于MySQL中的锁还有隔离等级这类话题,其概念性的解释早已泛滥。记住其概念,算不上什么。更重要的是思考:他们的区别和联系在哪儿,为什么会有这样的概念。
1)MySQL的锁(Lock)分为行锁(Row Lock)和表锁(Table Lock),锁本身又分为读锁(Read Lock)和写锁(Write Lock)。
2)隔离等级分为Read uncommitted, Read committed, Repeatable reads, Serializable
3)在常见的读场景(Read phenomenon)中,会出现Dirty read, Non-repeatable reads以及Phantom Reads
为什么要这么分类,三个类别的概念是如何相互联系的。这里谈谈我的思考。
二、发现问题:Read phenomenon
所谓Dirty read,脏读,如下例所示
select age from students where id = 9
update table students set age = 12 where id = 9
select age from students where id = 9
rollback
脏读的关键在于,左侧的事务A中的第二次读操作读到了事务B并没有提交的数据,导致出错。关键点在于事务B还没有提交。
-------------------------------------------------------------------------------------------------------------------------------
所谓Non-repeatable reads,不可重复读,如下例所示
select age from students where id = 9
update table students set age = 12 where id = 9
commit
select age from students where id= 9
commit
不可重复读的关键,在于左侧的事务A中的第二次读操作读到了事务B中已经提交的数据,导致出错。关键点在于事务B已经提交。
-----------------------------------------------------------------------------------------------------------------------------------
Phantom Read,幻读,如下例所示
select * from students where id > 3 and id < 99
insert into students (id, name, age) values (12, "zs", 27)
commit
select * from students where id > 3 and id < 99
commit
幻读的关键,在于在集合统计层面上,出现了不可重复读,是一种特殊的不可重复读。不可重复读是修改数据,而幻读是新增数据。
-----------------------------------------------------------------------------------------------------------------------------------
那为什么要分为这三种层次的read phenomena?
这是因为,这三个层次实现了B事务的“缩小化”和“叠加”。从最开始B事务和A事务是交集状态,到后来B事务位于A事务内部, 再到最后由单个记录变为多条记录。本质上是这样一种递进关系。
二、分析问题:Isolation
为了依次避免上述每一个问题,就需要逐步采取更为严格的措施。这也就出现了隔离状态(Isolation)
1)啥都不避免,最烂的约束,就是Read uncommitted。这个uncommitted单词是有意味的,说白了就是未提交,也就是脏读中出现的情况。
2)避免脏读,就是Read committed。这个committed单词也是有意思的,是已提交。如此也就排除了脏读的情况,但是仍会有不可重复读和幻读的情况。
3)避免脏读和不可重复读,就是 Repeatable reads。对应的正好是non-repeatable。但是仍会有幻读情况。
4)避免所有情况,那就是Serializable。
三、解决解决:Lock
这样逐级进行分类,实际上也为解决这些问题提供了一种策略,那就是“锁”。
读锁(Read Lock)还有一个学名,叫做Shared Lock(共享锁)。写锁(Read Lock)也叫作排它锁(Exclusive Lock)
某线程一旦获得写锁,其他的线程都将无法获得任何锁,无论写锁还是读锁,都会被挂起,直到该写锁释放。
某线程获得了读锁,其他线程仍旧可以获得读锁,但无法获取写锁。直到读锁释放。
我们来锁看看是怎么解决上述read phenomena的
1)Read uncommitted。这个就是啥锁都不要。对吧。裸奔
2)Read committed。这个是要做到事务B能够完整提交,那好,就用一个写锁,保证事务B在执行过程中始终拥有一个写锁。至于事务A中的读,就不给锁了,或者换一个说法,每次select的时候会获得一个读锁,select操作完成后立即释放。总之读锁是不可能维持整个事务过程的。如此一来,避免了脏读,却无法避免不可重复读。
3)Repeatable reads。这下除了写锁,还得必须保证读锁了,也就是说,事务A必须拥有读锁,事务B必须有写锁,锁的生存期为整个事务过程。两者不可交叉。不可重复读的问题也解决了。
4)Serializable。如何克服统计层面上的幻读呢?现在我们不仅要保证单条数据记录的可重复读,还要保证多条记录在统计意义上的可重复读,那就是有采用表锁了(Table Lock),当然也不一定要锁全表,所以最为准确的说法,是用范围锁(Range Lock),把多条记录都上锁。讲到这里,也就很清楚了,1-3是不需范围锁的。
四、结语
锁,隔离等级,读场景,就是这么关联到了一起:发现问题,分析问题,解决问题。
MySQL中的锁、隔离等级和读场景的更多相关文章
- MySQL实战 | 06/07 简单说说MySQL中的锁
原文链接:MySQL实战 | 06/07 简单说说MySQL中的锁 本文思维导图:https://mubu.com/doc/AOa-5t-IsG 锁是计算机协调多个进程或纯线程并发访问某一资源的机制. ...
- 在MySQL中设置事务隔离级别有2种方法:
在MySQL中设置事务隔离级别有2种方法: 1 在my.cnf中设置,在mysqld选项中如下设置 [mysqld] transaction-isolation = READ-COMMITTED 2 ...
- 谈谈MySQL中的锁
谈谈MySQL中的锁 锁的定义 在生活中锁的例子就非常多了,所以应该很容易理解锁的含义.在计算机领域,可以这样来概述,锁是计算机协调多个进行进程并发访问某一资源的机制. 在数据库中,锁也是一个 ...
- MySQL系列(五)---总结MySQL中的锁
MySQL中的锁 目录 MySQL系列(一):基础知识大总结 MySQL系列(二):MySQL事务 MySQL系列(三):索引 MySQL系列(四):引擎 概述 MyISAM支持表锁,InnoDB支持 ...
- 你了解MySQL中的锁吗?
MySQL中的锁,分为全局锁.表级锁.行锁 全局锁 全局锁的意思就是,对整个数据库实例加锁,它的命令是FTWRL Flash tables with read lock 这个命令的语义是,使整个库处于 ...
- MySQL中InnoDB锁不住表的原因
MySQL中InnoDB锁不住表是因为如下两个参数的设置: mysql> show variables like '%timeout%'; +-------------------------- ...
- mysql中的锁表语句查看方法汇总
mysql> show status like 'Table%'; +----------------------------+----------+ | Variable_name | Val ...
- MySQL中的锁(表锁、行锁)
锁是计算机协调多个进程或纯线程并发访问某一资源的机制.在数据库中,除传统的计算资源(CPU.RAM.I/O)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所在有数 ...
- mysql中不同事务隔离级别下数据的显示效果--转载
事务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查询语句因为崩溃或其他原因而无法执行,那么所有的语句就都 ...
随机推荐
- Problem B: 深入浅出学算法003-计算复杂度
Description 算法复杂度一般分为:时间复杂度.空间复杂度.编程复杂度. 这三个复杂度本身是矛盾体,不能一味地追求降低某一复杂度,否则会带来其他复杂度的增加.在权衡各方面的情况下,降低时间复杂 ...
- hdu 3572 资源分配
资源分配,每个时间点有m个机器可用,要将这资源分配给n个任务中的一些,要求每个任务在自己的时间范围中被分配了p[i]个资源,建图: 建立源,与每个时间点连边,容量为m,每个任务向其对应的时间段中的每个 ...
- JavaScript设计模式与开发实践——读书笔记1.高阶函数(上)
说来惭愧,4个多月未更新了.4月份以后就开始忙起来了,论文.毕设.毕业旅行等七七八八的事情占据了很多时间,毕业之后开始忙碌的工作,这期间一直想写博客,但是一直没能静下心写.这段时间在看<Java ...
- [原]Android Studio导入外部项目找不到对应的sdk解决办法
示例项目:JPushExample(349872) 打开项目的文件夹目录,找到:JPushExample(349872)\app\build.gradle打开,将里面的 compileSdkVersi ...
- MyEclipse2015创建配置Web+Maven项目
首先我的MyEclipse版本是2015 stable 2.0,在MyEclipse中创建Maven项目通常有两种常见的方式,它们分别是: New Maven Project New Web Pro ...
- 再见了,DM
在DM奋斗了20个月之后,我终于有机会DM说再见.这我不是我第一次和DM说再见,因此我也不确定这次的再见是再也不见,还是再次见面.但有一点可以确定的是,在接下来相当长的一段时间内,我是没有机会 ...
- dtrace for mysql
http://dtrace.org/blogs/brendan/2011/06/23/mysql-performance-schema-and-dtrace/
- Unity3d面试6
1,如何避免点击UI按钮时穿透,同时触发了相同位置场景模型的点击事件的情况?(NGUI)1,如何避免点击UI按钮时穿透,同时触发了相同位置场景模型的点击事件的情况?(NGUI 判断 是否点击到UI) ...
- qt 中文乱码 处理QByteArray类型里含中文的数据
qt解析tcp通信传来的xml时,中文有乱码 解决方法: 头文件加入 #include <QTextCodec> QByteArray tmpQBA = m_pSocket->rea ...
- iOS开源项目:AudioPlayer
AudioPlayer是一个基于AVAudioStreamer的在线音乐播放软件. https://github.com/marshluca/AudioPlayer 首先将歌曲信息存储在NSArray ...