图解mysql事务的四个隔离级别

发布时间:2022-03-01 10:31:36 作者:yexindonglai@163.com 阅读(601)

什么是隔离级别

说到隔离级别,就要先谈到事务,因为隔离级别是基于事务而存在的,

事务

事务指的是多个数据同时修改时,要么一起成功,要么一起失败。事务就像是小时候玩超级玛丽一样,你每次过关,都必须在没有死亡的情况下才能过关,只要有一次死亡,那么这一关就得重新开始;超级玛丽不存在中途继续的情况,重新开始就意味着回滚(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. 使用间隙锁
  2. 使用串行化隔离级别

四大隔离级别

1、读未提交

read uncommitted 只要修改了数据,不管有没提交,其他事物都可以马上看到数据,用java来举例,就相当于每个数据都加了volatile关键字保证了其他线程的可见性;
mysql 修改隔离级别为 读未提交 命令如下

  1. set session transaction isolation level read uncommitted;

读未提交的缺陷

是在并发场景下,这种隔离级别没有解决任何问题,所以基本没什么人用;

2、 已提交读/读已提交

READ COMMITTED 已提交读也可以成为读已提交,已提交读可以解决脏读的问题,它的级别比读未提交要高,所以,将隔离级别设置为读已提交后,其他事物修改了数据必须提交后,当前事务才可以看到;
mysql 修改隔离级别为 读已提交 命令如下

  1. set session transaction isolation level read committed;

已提交读的缺陷

虽然读已提交可以解决脏读问题,但是不能解决不可重复读的问题,但是它的效率高,所以oracle、sql Server等数据库的默认隔离级别就是读已提交;

3.、可重复读

Repeatable Read 可重复读是mysql 的默认隔离级别,可重复读是为了解决同一个事务下,每次查询的结果必须是一致的,

  • 比如A事务读取id1的数据,amount为100
  • B事务将amount修改为98
  • A事务再去查询时amount 还是100 ,不受B事务修改的影响

这样就做到了不同事务之间的行数据彻底隔离;互不影响;设置可重复读的sql如下

  1. set session transaction isolation level repeatable read;

在这里插入图片描述
可重复读的缺陷

可重复读虽然能保证事务的一致性,因为可重复读只能保证同一行数据的事务,也就是行锁,如果我插入的新的行记录,就无法保证一致性了,也就无法解决幻读的问题,

4.、串行化

Serializable 安全性最高的隔离界别,效率也最慢,这种隔离级别就相当于是表锁,每次修改数据时都会将整张表锁住,哎,那这不就是myisam了吗?没错,串行化就是和myisam一样了;串行化的隔离级别,在java中就和synchronized 关键字一样了;每次修改的时候只能有一个线程进行修改,其他线程只能在外面排队等着;那么多人排成串在那等,效率肯定是最慢的了;
在这里插入图片描述

mysql 设置可串行化隔离级别的sql如下

  1. set session transaction isolation level serializable;

关键字Mysql