读未提交-为什么可以读到别人修改的数据

本文探讨了数据库事务中的脏读问题,解释了数据库事务提交的本质并非与数据修改同步,而是数据修改先存储在数据库缓存池中。MySQL的InnoDB通过MVCC实现事务隔离,即使事务未提交,数据也可能在缓存中变为可见。解决脏读的方法包括使用读写锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

疑惑

​ 之前在思考数据库隔离级别的时候,读到"脏读"问题,也就是第一次读到的数据跟第二次读到的不一样,这种情况一般发生在数据库隔离级别为RR即repeatable readable,这种情况下,可能会思考为什么他事务没提交我就能读到数据了呢?这个问题理解的核心在于,数据库事务的提交和数据的修改提交根本不是一回事。

分析

首先解释一下数据库事务提交的本质,也就是commit操作:

  1. commit操作的作用不是把缓存或者内存中的数据更新到数据库
  2. 本质就是代表一次事务结束
  3. commit之前,数据修改已经更新到数据库缓存池中了

再来解释,修改的数据是怎么被读到的,也就是commit之前修改的数据存在哪里:

以MySQL为例

“数据未提交,那数据库应该没有改变”,这个假设其实是错误的。数据库的底层设计都使用了WAL(Write-ahead**Logging)思想,只不过数据库的事务隔离技术了提供了各种方案,一个数据库请求即使事务没有提交也会发生数据库内部数据的变更,有各种技术,像Mysql InnoDB MVCC,只不过是通过一些字段进行控制。

在数据库没有提交数据的时候,你更新的数据是在缓存进行更新的,事务与事务在并发进行的时候就叫作隔离级别,只有在提交之后,数据才从日志中把数据更新到数据库里面。

目前主流的关系型数据库例如mysql、Oracle都是基于文件系统进行数据存储的,即数据是持久化到文件系统的,但基于文件系统的随机IO读写是非常慢的,故数据库都会引入内存池,完成对磁盘数据的缓存,提高读写性能。内存池是对所有线程共享的,也就是对所有的数据库事务是共享的,所谓的未提交,指的是事务未提交,但此时数据已经存储到了共享内存中,数据已经进入到了数据库服务器中,所以是可见的。

这个问题要根据不同数据库来具体分析,以MySQL为例:

MySQL的InnoDB,实现事务是根据MVCC多版本并发控制(乐观锁实现)

  1. InnoDB里每个事务都有自己唯一的事务ID,新来的事务会自增
  2. 同时每一行数据都有两个隐藏列,一个记录事务id,一个记回滚指针
  3. 当一行数据同时被多个事务修改,这行数据就会有n个不同事务id的"“复制”
  4. 所以在读未提交这种隔离级别下,你可以读到别人没有提交的修改数据

解决办法

读的时候加S锁

写的时候加X锁

至于为什么,自己思考一下

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值