脏读,不可重复读,幻读以及四种隔离级别

布鸽不鸽 Lv4

前言

在事务中,我们常听到脏读,不可重复读,幻读这三种概念。本文将根据例子来讨论这三种问题。同时,再依次谈谈解决上述问题的三种隔离级别。
原文地址:https://xuedongyun.cn/post/64889/

脏读

脏读的定义

脏读,又称为“读未提交”,就是事务A读取到了事务B已修改但未提交的数据

我们来看一个例子:假设age原本是13。事务B修改age后,被事务A读到了,但是事务B最后回滚了。也就是说,事务A读到了事务B修改但未提交的数据。

事务A事务B
开始事务开始事务
修改age(从13改为23)
查询age(age=23)
commitrollback(回滚,age实际上还是13)

解决脏读的隔离级别

我们可以使用READ_COMMITTED这个隔离级别来解决脏读的问题。READ_COMMITTED要求事务A只能读取其他事务已提交的修改

1
@Transactional(isolation = Isolation.READ_COMMITTED)

不可重复读

不可重复读的定义

不可重复读,又称为“读已提交”,就是事务A中多次读取数据,读取到的结果不一样

我们来看一个例子:在事务A中,先查询了一次,age=13。此时事务B修改并提交。在事务A中,又查询了一次,此时事务B已提交,所以能成功读取,但此时age=23,已经和之前不一致了

事务A事务B
开始事务开始事务
查询age(age=13)
修改age(从13改为23)
commit
查询age(age=23)
commit

解决不可重复读的隔离级别

我们可以使用REPEATABLE_READ这个隔离级别来解决脏读的问题。REPEATABLE_READ要求事务A执行时,其他事务禁止对这个字段进行修改

1
@Transactional(isolation = Isolation.REPEATABLE_READ)

这也是MySQL的默认隔离级别

幻读

幻读的定义

幻读,就是事务A前后两次读取中,事务B插入或者删除数据,从而发生的一种类似幻觉的现象

我们来看一个例子:事务A前后两次查询id=1001的用户,第一次找不到,第二次又找到了。这是因为在两次查询之间,事务B插入了新的数据。(REPEATABLE_READ只限制了不能修改,没有限制增删)

事务A事务B
开始事务开始事务
查询id=1001的用户,发现没找到
插入id=1001的用户
commit
查询id=1001的用户,发现又能找到了
commit

解决幻读的隔离级别

我们可以使用SERIALIZABLE这个隔离级别来解决脏读的问题。SERIALIZABLE要求事务A执行时,其他事务禁止对这个表进行添加、更新、删除操作

1
@Transactional(isolation = Isolation.SERIALIZABLE)

总结

三种问题

  • 脏读:读到了已修改但未提交的数据
  • 不可重复读:前后两次读取的结果不一样
  • 幻读:之前读取存在,再读发现不存在了(或者反之亦然)

四种隔离级别

  • READ UNCOMMIT:最低的级别,能读到未提交的数据
  • READ COMMIT:只能读修改已提交的数据
    • 解决:脏读
  • REPEATABLE READ:读取期间,其他事务不能对该字段进行修改
    • 解决:脏读,不可重复读
  • SERIALIZABLE:读取期间,其他事务不能对这个表进行增删改
    • 解决:脏读,不可重复读,幻读
  • 标题: 脏读,不可重复读,幻读以及四种隔离级别
  • 作者: 布鸽不鸽
  • 创建于 : 2023-06-17 19:13:17
  • 更新于 : 2024-01-06 18:38:04
  • 链接: https://xuedongyun.cn//post/64889/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论