MySQL - 事务隔离级别

并发事务问题

脏读

概念: 一个事务读到另外一个事务还没提交的数据

举例:

事务A:第一步:select 第二步:update 第三步:...

事务B:第一步:select 第二步:...

假设原本在数据库中的 数据C = 1,那么

  1. 事务A进行到第二步修改了数据库中的 数据C =2
  2. 此时事务B开始第一步,读取事务A修改后的 数据C=2
  3. 但是此时事务A未将事务提交,有可能会进行事务的回滚,数据C 被修改回原来的值 =1
  4. 而事务B此时持有的就是错误的 数据C =2

不可重复复

概念: 一个事务先后读取同一条记录,但两次读取到的数据不同

举例:

事务A:第一步:select 第二步:... 第三步:select

事务B:第一步:... 第二步:update 第三步:提交事务

  1. 事务A执行到第一步,查询 数据C =1
  2. 接着事务B 执行到第二步,修改了数据C =2
  3. 接着事务B 执行到第三步,提交了事务
  4. 接着事务A执行到第三步,再次查询数据C =2
  5. 但此时事务A发现,前后两次查询数据C的值不一样,这就出现了 不可重复读

幻读

概念: 一个事务按照查询条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在

举例:

事务A:第一步:select 第二步:insert 第三步:select

事务B:第一步:... 第二步:insert 第三步:提交事务

  1. 事务A要插入一条 id=1 的数据,第一步先查询数据库中是否有 id=1 的数据,发现没数据
  2. 接下来事务B 刚好执行到第二步,插入了一条 id=1 的数据
  3. 事务B执行到第三步,提交了事务
  4. 而事务A此时进行到第二步,要往数据库中插入 id=1 的数据,结果发现已经存在了
  5. 但是事务A接着执行第三步查询,结果查询到的结果还是没有

事务隔离级别设置方法

查看事务隔离级别

sql 复制代码
SELECT @@TRANSACTION_ISOLATION;

设置事务隔离级别

sql 复制代码
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED |
READ COMMITTED | REPEATABLE READ | SERIALIZABLE }

其中的 [ SESSION | GLOBAL ] 选择是只对当前会话进行设置还是对全局进行设置

事务隔离级别详解

读未提交(Read uncommitted)

效果 -- 相当于没有隔离,三种并发事务问题都会发生

虽然 读未提交的隔离级别 的数据安全性最差,但是性能最高,因为其并发程度最高

读已提交(Read committed)

Oracle的默认隔离级别

效果 -- 解决了脏读问题

例如上面的脏读例子:

事务A:第一步:select 第二步:update 第三步:提交

事务B:第一步:select 第二步:... 第三步:select

假设原本在数据库中的 数据C = 1,那么

  1. 事务A进行到第二步修改了数据库中的 数据C = 2
  2. 此时事务B开始第一步,读取的不再是事务A修改后的 数据C ,而是原本的值 数据C=1
  3. 等事务A将事务提交
  4. 事务B再次读取 数据C,才会读取到事务A修改的 数据C=2

这就解决了脏读问题

可重复读

MySQL的默认隔离级别

效果 -- 解决了 脏读、不可重复读 问题

例如上面的不可重复读例子:

事务A:第一步:select 第二步:... 第三步:select

事务B:第一步:... 第二步:update 第三步:提交事务

  1. 事务A执行到第一步,查询 数据C =1
  2. 接着事务B 执行到第二步,修改了数据C =2
  3. 接着事务B 执行到第三步,提交了事务
  4. 接着事务A执行到第三步,再次查询到的不是事务B已经提交的数据C=2,还是之前的C=1

这就解决了不可重复读的问题

串行化

效果 -- 解决了 脏读、不可重复读、幻读 问题

串行化就是同步,不存在并发,那肯定就没有并发事务问题

但是没有并发,也就意味着,串行化对性能的影响很大

举例:

事务A:第一步:select 第二步:insert 第三步:select

事务B:第一步:insert 第二步:... 第三步:提交事务

  1. 事务A要插入一条 id=1 的数据,第一步先查询数据库中是否有 id=1 的数据,发现没数据
  2. 接下来事务B 刚要开始执行第一步插入id=1的数据,但是此时因为事务A在进行,事务B不能并发,会被阻塞
  3. 必须等事务A进行到第二步,要往数据库中插入 id=1 的数据,接着执行后面的步骤直到提交事务
  4. 事务A提交后,事务B才会开始进行第一步,但是这个时候事务B就会发现id=1的数据已经存在,插入失败

这就解决了幻读的问题

总结

事务隔离级别越高,数据越安全,但是性能越低

相关推荐
qq_348231852 分钟前
MySQL 与 PostgreSQL PL/pgSQL 的对比详解
数据库·mysql·postgresql
玩转数据库管理工具FOR DBLENS22 分钟前
DBLens:开启数据库管理新纪元——永久免费,智能高效的国产化开发利器
数据结构·数据库·测试工具·数据库开发
芝麻馅汤圆儿29 分钟前
sockperf 工具
linux·服务器·数据库
IndulgeCui29 分钟前
金仓数据库征文_使用KDTS迁移mysql至金仓数据库问题处理记录分享
数据库
cui_win35 分钟前
Prometheus实战教程 - mysql监控
mysql·prometheus·压测
wsx_iot38 分钟前
mysql的快照读和当前读
数据库·mysql
梁萌43 分钟前
MySQL分区表使用保姆级教程
数据库·mysql·优化·分区表·分区·partitions
期待のcode1 小时前
MyBatis-Plus的Wrapper核心体系
java·数据库·spring boot·后端·mybatis
透明的玻璃杯1 小时前
sqlite数据库链接池二
数据库·oracle·sqlite
老华带你飞1 小时前
出行旅游安排|基于springboot出行旅游安排系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·spring·旅游