mysql事务传播级别_图解MySQL事务隔离级别

本文主要通过大量的实例截图,来通俗的讲解MySQL的四种事务隔离级别的效果。关于事务隔离级别的概念以及不同隔离级别会引发的问题,大家可以自行百度,此处不再赘述。

标准数据库的四种事务隔离级别,不同隔离级别会引发的问题:隔离级别脏读不可重复读幻读

Read UncommittedYYY

Read CommittedNYY

Repeatable ReadNNY

SerializableNNN

MySQL采用的默认隔离级别是Repeatable Read,我们可以用set global|session tx_isolation='xxx'和select @@global|session.tx_isolation来修改和查看global或session的隔离级别。下面我们一一介绍不同隔离级别在‘增删改’操作时的效果。

1. Read Uncommitted

当前数据库的隔离级别为Read Uncommitted

72acb661291dc45f7d121cee4ea4343b.png

①增:

session1开启事务,往company表插入一条数据,成功:

f3dc23c1e1b9b175281e5c3f8e4cda94.png

session2开启事务,查询company表,session1插入的未提交数据对session2可见。这就出现了脏读和幻读,因为对于session2来说莫名其妙的多出了一条未提交的数据;而且出现了不可重复读,因为这次读到的记录跟上一次读到的不一样:

b530b7a072854ad860df06000763a1fa.png

如果session2在不知情的情况下,又往数据库insert一条company_id为6的数据;又或者他以为company_id为6的数据是已经commit的数据,要对他进行update或者delete操作。那这些操作都会阻塞,直到session1完成事务为止,因为这条数据还在session1事务的管理中,后面可能还会发生变化:

68b7fd4ec77062a6b4b2589a9a851231.png

但如果session2不是修改的session1插入的数据,update、insert和delete是可以成功的,因为InnoDB采用的是行锁:

b3ce3eb8950a5a56fcacbb063f403062.png

②删:

session1开启事务,并从company表中删除一条记录:

3d0479f56bd9e7a1ca636ed4678dc6e9.png

session2开启事务,查询company表,session1删除后未提交数据对session2可见,典型的脏读。也出现了幻读,因为对于session2来说莫名其妙的少出了一条数据,而且出现了不可重复读,因为这次读到的记录跟上一次读到的不一样:

ed2ec9622dd1ca8d539879cfee636988.png

跟上面一样,如果session2对session1事务中操作的记录进行delete、insert和update会被阻塞,直到session1结束事务并释放行锁。而对其他行的delete、insert和update操作可以成功:

8fd69f4d87a96ca853d9ea7adb8a2c29.png

③改:

session1开启事务,并修改company表中的一条记录:

28baacda40414afacf836ba620f3bd77.png

session2开启事务,查询company表,session1修改后未提交数据对session2可见。但没有出现了幻读,因为对于session2来说数据量并没有改变,但出现了脏读和不可重复读,因为这次读到了session1未提交的修改数据而且记录跟上一次读到的不一样:

b0a182374b4109dc3c1829f347195e91.png

跟上面一样,如果session2对session1事务中操作的记录进行delete、insert和update会被阻塞,直到session1结束事务并释放行锁。而对其他行的delete、insert和update操作可以成功:

4a9b0a74f5605ca39d7925d03be14646.png

总结:Read Uncommitted隔离级别会出现:脏读、不可重复读和幻读。每个session在事务中的操作会对其他session事务立即可见,哪怕是未提交的操作。但当前session事务正在操作的数据,只要当前事务没有结束或者回滚,就无法被其他session修改,其他session会阻塞。

2. Read Committed

当前数据库的隔离级别为Read Committed

02ec01a12d10f5e7f26a8cb0b79382a1.png

①增:

session1开启事务,往company表插入一条数据,成功并且session1可以看到这条记录:

2ba605c47a6334de7b9693c0c660086f.png

session2开启事务,查询company表,session1插入的未提交数据对session2不可见。在session1没有提交之前不会出现幻读和不可重复读:

849aed52edb679377849d784e3ac89e0.png

但只要session1一提交就会出现幻读和不可重复读:

f1cbf5b0f430d853676ef9dd790a737f.png

ebdd65679ac0aac09a11d0d1f6780941.png

如果session2对session1事务中操作的记录进行delete、insert和update会被阻塞,直到session1结束事务并释放行锁。而对其他行的delete、insert和update操作可以成功:

②删:

session1开启事务,并从company表中删除一条记录:

7927747b7cae09351a197b0cc34e1c2b.png

session2开启事务,查询company表,session1删除后未提交数据对session2不可见。当然也没有出现幻读和不可重复读:

8e7d2fcd7c50dd27bd91bb23b53c0c81.png

但只要session1一提交就会出现幻读和不可重复读:

c582407540e20a8e0dac77f868322c77.png

22245a625aca18cbdc3295fe232d9db7.png

跟上面一样,如果session2对session1事务中操作的记录进行delete、insert和update会被阻塞,直到session1结束事务并释放行锁。而对其他行的delete、insert和update操作可以成功。

③改:

session1开启事务,并修改company表中的一条记录:

33bd71a90491f281a424464f2b437efc.png

session2开启事务,查询company表,session1修改后未提交数据对session2不可见。没有出现了幻读、脏读和不可重复读:

d4142c16197606168804b6bdd66654d1.png

但只要session1一提交就会出现不可重复读:

e818cebdef33804ba07ab0a83d01c0f5.png

4bea14c9708fae2187f6d5eddad9908b.png

跟上面一样,如果session2对session1事务中操作的记录进行delete、insert和update会被阻塞,直到session1结束事务并释放行锁。而对其他行的delete、insert和update操作可以成功。

总结:Read Committed隔离级别会出现:不可重复读和幻读。每个session在事务中的操作对其他session事务是不可见的。当前session事务中正在操作的数据,只要当前事务没有结束或者回滚,就无法被其他session修改,其他session会阻塞。一旦提交就可能会出现不可重复读和幻读。

3.Repeatable Read

当前数据库的隔离级别为Repeatable Read

69789a470af173e5c41500cd5b60fe94.png

①增:session1开启事务,往company表插入一条数据,成功:

3bf83a230fb0db94de3782f5805b6602.png

session2开启事务,查询company表,session1删除后未提交数据对session2不可见。当然也没有出现幻读和不可重复读:

a9d8b82cb4ee2fb3c9ca8794eb460789.png

session1提交后,session2也不会出现不可重复读:

a9d8b82cb4ee2fb3c9ca8794eb460789.png不是说Repeatable Read会出现幻读么,这里为什么没有多出一条记录?其实Repeatable Read隔离级别可以保证每次读取都是一样的记录,幻读只是说如果session2正在insert的数据和被session1插入的数据相同时会报duplicate key的错,因为session1已经插入了。这样让用户就会感到奇怪,为什么明明没有记录却无法插入呢:

74eb6a2219880d96e66d7935dcdaf976.png

②删:

session1开启事务,并从company表中删除一条记录:

7ed9c72af5ef50bb2e645c1699cdc5ae.png

session2开启事务,查询company表,session1删除后未提交数据对session2不可见。当然也没有出现幻读和不可重复读:

1d1571aaf0e11e26ad06251a57911113.png

session1提交后,session2也不会出现不可重复读。但幻读存在,因为如果我们去delete或者updatesession1已经删掉的记录时,会显示受影响的记录为0;而去insert一个跟删掉的记录同样company_id的记录却可以成功,说明记录实际上已经不存在了:

dcc1546511836ba33572f9aee33f271b.png

c5bb0071814e30e165cb623659097e93.png

③改:

session1开启事务,并修改company表中的一条记录:

04743fa40f7a52c86a83f89cc500f68a.png

session2开启事务,查询company表,session1修改后未提交数据对session2不可见。没有出现了幻读、脏读和不可重复读:

17c3000bb09fefc01948691a1b9c8dfd.png

session1提交后,session2也不会出现不可重复读。跟上面一样幻读依旧存在,如果我们去根据session1修改后的条件去update或者delete记录时可以成功,说明记录实际上已经被修改了:

4279cfca27c4fa04ad5e28ce2871f8ba.png

总结:Repeatable Read隔离级别会出现:幻读。每个session在事务中的操作对其他session事务是不可见的。当前session事务中正在操作的数据,只要当前事务没有结束或者回滚,就无法被其他session修改,其他session会阻塞。一旦提交就可能会出现幻读。所以Repeatable Read相当于生成一个数据库记录的快照,表面上每次读取的数据都一样吗,但实际上有可能已经发生了变化。

4.Serializable

当前数据库的隔离级别为Serializablef62f9f647f0467d4844c89e123af0f24.png

Serializable主要是使用InnoDB的行锁来实现的,增删改都是加行锁,所以下面就只讨论增的情况:session1开启事务,往company表插入一条数据,成功:

23232af9540a73cc85984c06ee852486.png

session2开启事务,查询company表时直接被阻塞,查询刚插入的数据时也被阻塞,但查询其他数据时却没问题。说明采用Serializable隔离级别时,利用了InnoDB行锁的特性,谁修改列谁就能获得列的写锁,所以其他session是无法读取和写入的。第一个全表查询包括了刚被session1插入的数据,所以被阻塞:

38f03fd7309a24efa3ad9f854cc3873e.png如果我们现在回到session1里面去修改company_id=1的记录可以成功吗?结果是被阻塞,因为该记录已经被session2读取的同时也被session2加上了读锁。所以session1可以读取,但无法写入:

194d6d48bfbbd7922bfe35a75cec410b.png

这种情况下脏读、不可重复读和幻读都不可能出现,因为其他事务修改的记录,当前事务根本没机会读取;而被当前事务读取的数据,其他事务根本没机会修改。

Serializable是一种完全同步机制,所以很容易出现死锁,所以要特别注意,下面我们来看看死锁的例子:

首先session1和session2分别取出company_id为1和2的两条数据,根据上面的例子我们可以知道,session1会给company_id=1的记录加读锁,session2也会给company_id=2的记录加读锁:

d482364838b176573f38dd8ec1f61aa6.png

d16dad66b52608c6846fdf94db2c02a7.png

然后让session1去更新company_id=2的记录,肯定被阻塞;再让session2区更新company_id=1的记录,这时MySQL就会告诉我们出现了死锁,并强制关闭了session2的事务,让session1更新成功。之所以会出现死锁,因为session1要等待session2释放company_id=2的记录的读锁,而session2又要等待session1释放company_id=1的记录的读锁:

a3a5bc009ee0eb1892ab86b0b50559da.png

2464a0f757cbc1da266e64be52cf4a72.png

总结:Serializable主要是使用InnoDB的行锁来实现的,在事务中只要select出来的行都会被当前session加上read锁,如果去修改有read锁的行会被升级为write锁,没有read锁的行则直接加write锁。所以Serializable隔离级别不会出现脏读、不可重复读和幻读(第一次读的时候已经给行加read锁,其他session根本无法修改select出来的行,所以就保证了多次读取的一致性)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值