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的数据已经存在,插入失败

这就解决了幻读的问题

总结

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

相关推荐
用户982863025688 小时前
pg内核实现细节
数据库
码界筑梦坊8 小时前
330-基于Python的社交媒体舆情监控系统
python·mysql·信息可视化·数据分析·django·毕业设计·echarts
飞升不如收破烂~8 小时前
Redis 分布式锁+接口幂等性使用+当下流行的限流方案「落地实操」+用户连续点击两下按钮的解决方案自用总结
数据库·redis·分布式
workflower8 小时前
业务需求-假设场景
java·数据库·测试用例·集成测试·需求分析·模块测试·软件需求
亓才孓8 小时前
[JDBC]基于三层架构和MVC架构的JDBCTools
数据库
IT邦德8 小时前
RPM包快速安装Oracle26ai
数据库·oracle
Dovis(誓平步青云)8 小时前
《滑动窗口算法:从 “暴力遍历” 到 “线性高效” 的思维跃迁》
运维·服务器·数据库·算法
mr_LuoWei20098 小时前
python工具:python代码知识库笔记
数据库·python
这周也會开心9 小时前
Redis数据类型的底层实现和数据持久化
数据库·redis·缓存
ん贤9 小时前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁