【holm】MySQL事务隔离级别以及并发情况下出现的常见问题

MissFuTT 2020-05-11

总览

MySQL事务隔离级别

  • read uncommitted 读取未提交的数据
  • read committed 读取提交的数据
  • repeatable read 可重复读
  • serializable 串行化

常见问题

  • 更新丢失————事务A的操作被事务B覆盖
  • 脏读————事务A读取了事务B已经修改但尚未提交的数据,若事务B回滚,则事务A读取到的数据为脏数据
  • 不可重复读————事务A执行操作时两次读取数据不一致
  • 幻读————再解决不可重复读问题的基础上,可能无法根据查询到的值进行修改表数据。例如事务A无法插入一条自己事务内查询不到但事务B已经插入的相同数据,原因是事务B在事务A开始之后进行的插入...

MySQL相关操作

  • MySQL之后隔离级别的关键字为transaction_isolation
  • MySQL8之前隔离级别的关键为tx_isolation
  • 隔离级别的作用范围有GLOBALSESSION

查看隔离级别

  • show [GLOBAL|SESSION] VARIABLES like ‘transaction_isolation‘
  • SElECT @@transation_isolation

设置隔离级别

  • SET [SESSION|GLOBAL] transaction_isolation=[0|1|2|3]

read uncommitted

  • 此隔离级别中,所有事务都可以看到其他未提交事务的执行结果。(很少使用,舍弃了所有安全性的同时并没有明显性能提升)

问题:出现脏数据

read committed

  • 此隔离级别中,一个事务只能看见已提交事务所做的改变。

问题:不可重复读

repeatable read

  • MySQL默认的事务隔离级别
  • 此隔离级别可以确保同一事务内相同的查询语句执行结果一致

问题:幻读

实例:

-- 事务一
BEGIN;
SELECT * FROM table00;
/*
查询结果:
|id|name|
|-|-|
|1|wu|
*/

-- 此时系统遇到并发,首先执行完事务二

INSERT INTO table00 VALUES(2,"we"); -- 执行失败

SELECT * FROM table00;
/*
查询结果不变:(可重复读但出现幻觉——明明不存在却无法插入)
|id|name|
|-|-|
|1|wu|
*/

COMMIT;

-- 事务二
BEGIN;
SELECT * FROM table00;
/*
查询结果:
|id|name|
|-|-|
|1|wu|
*/
INSERT INTO table00 VALUES(2,"we"); -- 插入
SELECT * FROM table00;
/*
查询结果: (成功插入)
|id|name|
|-|-|
|1|wu|
|2|we|
*/
COMMIT;

避免幻读

  • 乐观锁为理论基础的MVCC(多版本并发控制)
  • 间隙锁

serializable

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突。换言之,它会在每条select语句后自动加上lock in share mode,为每个查询操作施加一个共享锁。在这个级别,可能导致大量的锁等待现象。该隔离级别主要用于InnoDB存储引擎的分布式事务。

隔离级别的选择(注意这部分是纸上谈兵,算是学习到现在的个人见解和猜测吧)

  • 并发量很少的情况下可以考虑选择串行化级别,一般来说面向用户尽可能不用此隔离级别。
  • 接着就是使用用户体验较好的乐观锁
  • 在高并发情况下增加消息队列对大量请求进行处理

参考资料

相关推荐