图解mysql事务的四个隔离级别
Posted java叶新东老师
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图解mysql事务的四个隔离级别相关的知识,希望对你有一定的参考价值。
什么是隔离级别
说到隔离级别,就要先谈到事务,因为隔离级别是基于事务而存在的,
事务
事务指的是多个数据同时修改时,要么一起成功,要么一起失败。事务就像是小时候玩超级玛丽一样,你每次过关,都必须在没有死亡的情况下才能过关,只要有一次死亡,那么这一关就得重新开始;超级玛丽不存在中途继续的情况,重新开始就意味着回滚(rollback),过关就代表提交(commit);
myisam
众所周知,,myisam是不支持事务的,所以myisam的每次修改数据时都是串行化的,也就是表锁;
innodb
mysql中只有innodb才支持事务,innodb支持表锁和行锁,innodb锁的对象是索引,聊到innodb的索引,肯定要牵扯到事务,事务有4个属性,称为ACID属性
原子性(Actimicity): 事务是原子操作,要么同时修改,要么同时回滚
一致性(Consistent):事务完成时必须保证数据一致性
隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作时影响独立的环境之下
持久性(Durable):也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
隔离级别能解决什么问题
而今天我们就要讲mysql的隔离性,隔离级别是为了解决脏读、不可重复读、幻读问题的,四个隔离级别分别为:
需要注意的是,隔离级别虽然解决了安全问题,但是并发效率却随着级别的升高而降低;也就是说越安全、效率越低;串行化可解决所有问题,但效率最低
事务出现的问题
mysql是一个并发数据库,也就是支持多个用户同时修改的情况,那么有多个用户修改,就会有多个事务,多事务高并发的情况下会出现什么问题呢?直接告诉你吧,就是上面讲的,会出现脏读、不可重复读、幻读的情况;
脏读
比如有下图的用户表,表中只有一条数据,
- A事务第一次读这条数据,amount为100,没问题,
- 然后在这中间,有一个B事务修改了其中一条信息,将
amount
改为98
,但是这时候B事务还没提交数据
, - 在这间隙里,A事务又查询了一次数据,查到了B事务未提交的数据,
这就是脏读;如果A事务将这个未提交的数据拿来使用,而事务B又回滚的话,将会出现很大的问题;会出现数据不一致的问题
不可重复读
还是那一行数据;
- A事务第一次读这条数据,amount为100,没问题,
- 然后在这中间,有一个B事务修改了其中一条信息,将
amount
改为98
,并且提交了B事务
- A事务在读这条数据时,得到的结果是98,
同一个事务,两次查询到的数据不一样,如果有多次查询同一条数据,每次查询到的数据都不一样,你是不是会很抓狂? 不可重复读的危害其实也不大,因为oracle默认的隔离级别就是不可重复读;所以oracle的效率要比mysql高;
幻读
还是那一行数据;
- A事务第一次查询所有的数据,结果只有一行,没问题
- 然后在这中间,有一个B事务插入了一条新的数据;
- A事务在查询所有数据,结果变成了2行数据,就像出现了幻觉一样;
这种现象叫做幻读;幻读会有数据一致性的问题,明明同一个事务,查询出来的数据却不一致,
行锁可以解决不可重复读的问题,但是不能解决幻读问题;如果要解决幻读,有2种方法
- 使用间隙锁
- 使用串行化隔离级别
四大隔离级别
1、读未提交
read uncommitted
只要修改了数据,不管有没提交,其他事物都可以马上看到数据,用java来举例,就相当于每个数据都加了volatile
关键字保证了其他线程的可见性;
mysql 修改隔离级别为 读未提交
命令如下
set session transaction isolation level read uncommitted;
读未提交的缺陷
是在并发场景下,这种隔离级别没有解决任何问题,所以基本没什么人用;
2、 已提交读/读已提交
READ COMMITTED
已提交读也可以成为读已提交,已提交读可以解决脏读的问题,它的级别比读未提交要高,所以,将隔离级别设置为读已提交后,其他事物修改了数据必须提交后,当前事务才可以看到;
mysql 修改隔离级别为 读已提交
命令如下
set session transaction isolation level read committed;
已提交读的缺陷
虽然读已提交可以解决脏读
问题,但是不能解决不可重复读
的问题,但是它的效率高,所以oracle、sql Server等数据库的默认隔离级别就是读已提交;
3.、可重复读:
Repeatable Read
可重复读是mysql 的默认隔离级别,可重复读是为了解决同一个事务下,每次查询的结果必须是一致的,
- 比如A事务读取
id
为1
的数据,amount
为100 - B事务将
amount
修改为98
- A事务再去查询时
amount
还是100
,不受B事务修改的影响
这样就做到了不同事务之间的行数据彻底隔离;互不影响;设置可重复读的sql如下
set session transaction isolation level repeatable read;
可重复读的缺陷
可重复读虽然能保证事务的一致性,因为可重复读只能保证同一行数据的事务,也就是行锁,如果我插入的新的行记录,就无法保证一致性了,也就无法解决幻读的问题,
4.、串行化
Serializable
安全性最高的隔离界别,效率也最慢,这种隔离级别就相当于是表锁,每次修改数据时都会将整张表锁住,哎,那这不就是myisam了吗?没错,串行化就是和myisam一样了;串行化的隔离级别,在java中就和synchronized 关键字一样了;每次修改的时候只能有一个线程进行修改,其他线程只能在外面排队等着;那么多人排成串在那等,效率肯定是最慢的了;
mysql 设置可串行化隔离级别的sql如下
set session transaction isolation level serializable;
完
以上是关于图解mysql事务的四个隔离级别的主要内容,如果未能解决你的问题,请参考以下文章