MySQL 四种事务隔离级别详解介绍(二)

Wesley13
• 阅读 372

参考文章:MySQL 四种事务隔离级别详解介绍

事务特性ACID中,隔离性最为复杂,它指的是事务与事务之间不会互相影响,一个事务的中间状态不会被其他事务感知。事务的隔离性由低到高分为:Read uncommitted 、Read committed 、Repeatable read 、Serializable。不同的隔离性在并发事务下会引起不同的读现象:脏读、不可重复读和幻读

一、读现象及其区别

1、脏读(读取了未提交的数据)

  脏读又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,但是这种修改还没有提交(commit),然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的,这个数据就是是脏数据,依据脏数据所做的操作可能是不正确的。

MySQL 四种事务隔离级别详解介绍(二)

  例子:程序员小王妻子给小王转零花钱,但是不小心按错数字了,将1K按成了7K,但是还没最后提交,这时候小王正好查看自己的零花钱,发现这个月零花钱有7K,以为老婆开恩,非常高兴。但是小王妻子发现问题,马上回滚差点就提交了的事务,但是小王看到是7K。他看到的是他老婆还没提交事务时的数据。这就是脏读。小王,瞧把你美的。

2、不可重复读(一个事务范围内两个相同的查询却返回了不同数据)

  不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。一种更易理解的说法是:在一个事务内,多次读同一个数据。在这个事务还没有结束时,另一个事务也访问该同一数据。那么,在第一个事务的两次读数据之间。由于第二个事务的修改,那么第一个事务读到的数据可能不一样,这样就发生了在一个事务内两次读到的数据是不一样的,因此称为不可重复读,即原始读取不可重复,读取数据不一样。

MySQL 四种事务隔离级别详解介绍(二)

  例子:程序员小王拿着工资卡去Happy(卡里当然只有可怜1K),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有1K,就在这个时候!小王的妻子发现小王去Happy,就把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待小王妻子转出金额事务提交完)。小王就会很郁闷,明明卡里是有钱的。小王,你还是太天真了。

3、幻读(一个事务范围内操作不完整的现象,它对应的是插入Insert操作,而不是Update操作)

  幻读是事务非独立执行时发生的一种现象,它是指B事务读取了两次数据,在这两次的读取过程中A事务添加了数据,B事务的这两次读取出来的集合不一样(集合数量或者集合中的元素)。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

MySQL 四种事务隔离级别详解介绍(二)

  例子:程序员小王某一天去Happy,花了1K元,然后他的妻子去查看他今天的消费记录(全表扫描,妻子事务开启),看到确实是花了1K元,就在这个时候,小王又花了1万元,即Insert了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现小王花了1.1万元,似乎出现了幻觉,这就是幻读。小王,等着跪键盘吧。

脏读

某一事务读取了另一事务未提交的脏数据

不可重复读

某一事务分别读取了另一事务提交前和提交后的数据

幻读

幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是幻读强调的集合的增减(Insert),不可重复读强调的是读取数据的修改(Update)

二、隔离级别锁实现机制

排他锁

被加锁的对象只能被持有锁的事务读取和修改,其他事务无法在该对象上加其他锁,也不能读取和修改该对象

共享锁

被加锁的对象可以被持锁事务读取,但是不能被修改,其他事务也可以在上面再加共享锁

特别的,对共享锁:如果两个事务对同一个资源上了共享锁,事务B想更新该数据,那么它必须等待事务A释放其共享锁

三、隔离级别 

1、未提交读(Read uncommitted)

定义

未提交读是最低的隔离级别,在这种事务隔离级别下,一个事务可以读到另外一个事务未提交的数据

锁机制

采用的是一级封锁协议

a、事务在读数据的时候并未对数据加锁;

b、事务在修改数据的时候只对数据增加行级共享锁,直到事务结束才释放。

操作逻辑

a、事务1读取某行记录时,事务2也能对这行记录进行读取、更新(因为事务1并未对数据增加任何锁)

b、当事务2对该记录进行更新时,事务1再次读取该记录,能读到事务2对该记录的修改版本(因为事务2只增加了共享读锁,事务1可以再增加共享读锁读取数据),即使该修改尚未被提交,导致“脏读”

c、事务1更新某行记录时,事务2不能对这行记录做更新,直到事务1结束。(因为事务一对数据增加了共享读锁,事务二不能增加排他锁进行数据的修改)

缺点

不能避免脏读,不可重复读,幻读

2、提交读(Read committed)

定义

提交读也可以翻译成读已提交,在一个事务修改数据过程中,如果事务还没提交,其他事务不能读该数据

锁机制

采用的是二级封锁协议

a、事务对当前被读取的数据加行级共享锁,一旦读完该行,立即释放该行级共享锁(非事务结束);

b、事务在更新某数据的瞬间,必须先对其加行级排他锁,直到事务结束才释放。

操作逻辑

a、事务1在读取某行记录的整个过程中,事务2都可以对该行记录进行读取(因为事务1对该行记录增加行级共享锁的情况下,事务2同样可以对该数据增加共享锁来读数据。)。

b、事务1读取某行的一瞬间,事务2不能修改该行数据,但是,只要事务1读取完该行数据,事务2就可以对该行数据进行修改。当事务1再次读取该行数据,并结束事务,与第一次读取的不一致,导致了不可重复读。(事务1在读取的一瞬间会对数据增加共享锁,任何其他事务都不能对该行数据增加排他锁。但是事务1只要读完该行数据,就会释放行级共享锁,一旦锁释放,事务2就可以对数据增加排他锁并修改数据

c、事务1更新某行记录时,事务2不能对这行记录做更新,直到事务1结束。(事务1在更新数据的时候,会对该行数据增加排他锁,知道事务结束才会释放锁,所以,在事务1没有提交之前,事务2都能不对数据增加共享锁进行数据的读取。所以,提交读可以解决脏读的现象

缺点

不能避免不可重复读,幻读

3、可重复读(Repeatable reads)

定义

由于提交读隔离级别会产生不可重复读的读现象。所以,比提交读更高一个级别的隔离级别就可以解决不可重复读的问题

锁机制

a、事务在读取某数据的瞬间,必须先对其加行级共享锁,直到事务结束才释放;

b、事务在更新某数据的瞬间,必须先对其加行级排他锁,直到事务结束才释放。

操作逻辑

a、事务1在读取某行记录的整个过程中,事务2都可以对该行记录进行读取(因为事务1对该行记录增加行级共享锁的情况下,事务2同样可以对该数据增加共享锁来读数据。)。

b、事务1在读取某行记录的整个过程中,事务2都不能修改该行数据(事务1在读取的整个过程会对数据增加共享锁,直到事务提交才会释放锁,所以整个过程中,任何其他事务都不能对该行数据增加排他锁。所以,可重复读能够解决不可重复读的读现象

c、事务1更新某行记录时,事务2不能对这行记录做更新,直到事务1结束。(事务1在更新数据的时候,会对该行数据增加排他锁,知道事务结束才会释放锁,所以,在事务2没有提交之前,事务1都能不对数据增加共享锁进行数据的读取。所以,提交读可以解决脏读的现象

缺点

不能避免幻读

4、可序列化(Serializable)

定义

是最高的隔离级别,前面提到的所有的隔离级别都无法解决的幻读,在可序列化的隔离级别中可以解决

锁机制

a、事务在读取数据时,必须先对其加表级共享锁 ,直到事务结束才释放;

b、事务在更新数据时,必须先对其加表级排他锁 ,直到事务结束才释放。

操作逻辑

a、事务1正在读取A表中的记录时,则事务2也能读取A表,但不能对A表做更新、新增、删除,直到事务1结束。(因为事务1对表增加了表级共享锁,其他事务只能增加共享锁读取数据,不能进行其他任何操作)

b、事务1正在更新A表中的记录时,则事务2不能读取A表的任意记录,更不可能对A表做更新、新增、删除,直到事务1结束。(事务1对表增加了表级排他锁,其他事务不能对表增加共享锁或排他锁,也就无法进行任何操作)

备注

a、无法读取其它事务已修改但未提交的记录。

b、在当前事务完成之前,其它事务不能修改目前事务已读取的记录。

c、在当前事务完成之前,其它事务所插入的新记录,其索引键值不能在当前事务的任何语句所读取的索引键范围中。

5、综述

隔离级别

脏读

不可重复读

幻读

Read uncommitted

Yes

Yes

Yes

Read committed

No

Yes

Yes

Repeatable reads

No

No

Yes

Serializable

No

No

No

  特别说明:大多数数据库默认的事务隔离级别是Read committed,比如Sql Server , Oracle。Mysql的默认隔离级别是Repeatable read

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
OMG!Java高级开发岗必问知识点
目录1.Mysql2.CHAR与VARCHAR的区别?3.能说下myisam和innodb的区别吗?4.你能说下事务的基本特性和隔离级别吗?5.并发问题脏读、不可重复读、幻读?6.事务的隔离级别?7.说说自增主键、UUID?8.mysql的约束分类?9.drop、delete与tru
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这