跳至主要內容

MySQL事务的隔离级别

张威大约 4 分钟mysql事务

MySQL事务的隔离级别

隔离级别概念

事务的隔离级别就是对事务并发的控制

MySQL支持的四种隔离级别是:

  1. TRANSACTION_READ_UNCOMMITTED:未提交读。说明在提交前事务A可以看到事务B的变化。这样都是可能发生的。

  2. TRANSACTION_READ_COMMITTED:已提交读(oracle默认),说明读取未提交的数据是不允许的(防止脏读)。在这个级别可能发生的。

  3. TRANSACTION_REPEATABLE_READ:可重复读(MySQL默认),说明事务保证能够再次读取相同的数据而不会失败,即使其他的事务把这个数据改了,你也不会看到前后两次查询的数据的不同,完全可以保证两次查询的结果是一样的,但是仍然会出现。

  4. TRANSACTION_SERIALIZABLE:串行化,是最高的事务隔离级别,它防止脏读,不可重复读和幻读。串行执行,,一般不会用

  • 事务隔离级别越高,为避免冲突所花费的性能也就越多

  • 在可重复读级别,实际上可以解决部分()的幻读问题,但是更新产生的幻读问题,要禁止幻读产生,还是需要设置串行化隔离级别

两个MySQL客户端默认工作在可重复读级别

查看隔离级别

select @@tx_isolation;	#MySQL5.7
select @@transaction_isolation; #8.0

测试read-uncommi隔离级别

  • 两个会话都需要设置成read-uncommitted隔离级别
  • 注意要加单引号
  • 可以看到一个客户端读到了另一个客户端未提交的数据-脏读
image-20240419155523434
image-20240419155523434

测试TRANSACTION_READ_COMMITTED隔离级别

由于设置了已提交读隔离级别,事务B并没有发生脏读,这是由各种锁机制以及事务并发的MVCC版本控制实现的

查询到了已经commit的数据,发生了不可重复读,这在已提交读隔离级别是允许发生的

既然发生了不可重复读,幻读就肯定可以发生了

测试TRANSACTION_REPEATABLE_READ隔离级别

image-20240419161539787
image-20240419161539787

可重复读隔离级别:对于一个事务来说,可以放心读数据,就算有其他事务修改了数据并且已经提交了,也不会在当前事务表现出来只要自己没改,数据都是不会变的

在可重复读隔离级别,测试幻读(在一定程度上防止了幻读,但没有完全防止

  • 可以看到,在当前的可重复读隔离级别,右侧事务无法查询到左侧事务insert的数据,虽然看不到,但

右边的客户端update左侧客户端insert的数据:

实际上,事务A已经插入并且提交了,aaa已经存在,所以事务B update aaa的年龄成功了

前后两次同样的查询,后一次查询与前一次查询的数据量不同,就发生了幻读。也就是可重复读隔离级别下,并没有解决幻读的问题,要彻底解决幻读,就需要设置串行化隔离级别

测试TRANSACTION_SERIALIZABLE隔离级别

由于

MySQL server不会让自己执行事务的线程永远阻塞,导致当前线程占用的锁无法释放,而使得其他执行事务的线程也无法获得锁而永远阻塞。所以