当前位置:首页 > 简单的说说 Mysql 的事务隔离

简单的说说 Mysql 的事务隔离

发布于 2019-05-27 阅读 156 次 Mysql

首先我们可以来看一张表,关于 Mysql 的事务隔离有如下几种:

事务隔离级别脏读不可重复读幻读加锁读
read-uncommittedYYYN
read-committedNYYN
repeatable-readNNYN
serializableNNNY

如何查询 Msyql 的事务隔离级别呢

#获取当前会话的事务隔离
select @@tx_isolation;

#获取当前系统的事务隔离级别
select @@global.tx_isolation;

通过上面的命令,可以下看 Mysql 当前的事务隔离级别为 repeatable-read

当前 Mysql 事务隔离级别

也就是 可重复读取 级别,这也是 mysql 的默认事务隔离级别。

为了进一步了解四种事务隔离有什么含义和区别,我们一起来看下面一个小例子
现有一张金额表 (account) :

idnamemoney
1张三100
2李四200

read-uncommitted (读未提交)

首先设置事务隔离为 read-uncommitted

# 设置当前会话 {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

# 设置当前系统
SET GLOBAL TRANSACTION ISOLATION LEVEL  READ UNCOMMITTED

有客户端 A 和 B 同时在操作金额表,过程如下:

客户端 A

客户端 B

客户端 A

A 已经可以读取到了 B 的更新操作,这看起来很美好。但事实上一点都不美好

把上面的过程画一张表:

客户端 A 客户端 B
开启事务
查询 张三 的金额 ( money = 100 )
开启事务
修改 张三 金额为增加 10 ( money = money + 10 )
查询 张三 的金额 ( money = 110 )
回滚事务

A 在①,② 中读取到的结果并不一致100 和 110。对他来说是糟糕的。最后 B 回滚事物,张三的金额回到 100,对 A 来说 ② 处读取是错误的,不可用。

这也就是 脏读:事物中可以读取其他事物的修改,即使是未提交的。

read-committed (读已提交)

既然可以读取到未提交的数据,导致脏读。那是不是可以想,只能读取已提交的数据呢?

同上我们把事务隔离设为 read-committed

客户端 A

客户端 B

客户端 A

A 查询 "张三" 的余额还是为 100,并没有获取到 B 未提交的修改,解决了脏读。

客户端 B

客户端 A

这时候我们应该可以发现了问题,最后一次读取跟前两次不一致🙅

客户端 A 客户端 B
开启事务
查询 张三 的金额 ( money = 100 )
开启事务
修改 张三 金额为增加 10 ( money = money + 10 )
查询 张三 的金额 ( money = 100 )
提交事务
查询 张三 的金额 ( money = 110 )

虽然解决了 ② 中的 脏读,A 事物中不能读取到 B 中未提交的事物,然而当 B 提交事物后 A 发现读取的数据又不一致了 wow amazing。这又产生了新的问题,不可重复读取

repeatable-read (可重复读取)

设置事务隔离为 repeatable-read,这也是 Mysql 的默认事务隔离

客户端 A

客户端 B

客户端 A

A 查询 "张三" 的余额还是为 100,并没有获取到 B 未提交的修改,解决了脏读。

客户端 B

客户端 A

当 B 提交事物后 A 查询 "张三" 的余额为 100,解决了不可重复读。

客户端 A 客户端 B
开启事务
查询 张三 的金额 ( money = 100 )
开启事务
修改 张三 金额为增加 10 ( money = money + 10 )
查询 张三 的金额 ( money = 100 )
提交事务
查询 张三 的金额 ( money = 100 )

repeatable-read 解决了脏读,不可重复读。保证了同一个事物中多次读取同样的数据的结果是一致的。但理论上,它还无法解决另外一个问题 幻读

什么是幻读呢?
A 开启事物:查询 account 表所有用户有:张三,李四

idnamemoney
1张三100
2李四200

B 开启事物,在 account 表中插入了一条数据:王五

idnamemoney
3王五300

A 再次查询 account 表所有用户

idnamemoney
1张三100
2李四200
3王五300

A 纳闷了,什么👻。怎么又多出来了一个王五,明明我是开启事物查询的。是不是我产生了幻觉啊。A 不相信又查了一次,还是3个账户。
幻读:某个事物在读取某个范围内的记录时,有另外一个事物在这个范围内插入了新记录,当之前的事物再次读取这个范围内记录时会产生幻读。

InnoDB由于使用了 MVCC 多版本并发控制,已经解决了幻读问题

serializable (可串行化)

最高的事物隔离级别,会在每一行的读取数据上都加上锁,而且这个锁属于共享表锁。所以容易导致大量的超时和争锁。非常影响性能。