MySQL读未提交隔离级别下,SELECT能否读取部分更新的行?
有可能,但具体取决于数据库的事务隔离级别和存储引擎的实现逻辑。
核心原理
单个UPDATE语句在关系型数据库中通常具备原子性:要么所有列的修改都完成并提交,要么全部回滚,不会将部分修改持久化到磁盘。但这并不意味着并行的SELECT绝对看不到中间状态,关键在于隔离级别是否允许读取未提交的中间版本。
分隔离级别说明
读未提交(Read Uncommitted):
这种隔离级别下,查询可以读取其他事务未提交的修改。如果UPDATE正在执行过程中(比如已修改col1但还未修改col2),理论上SELECT有可能读到col1=new_val1, col2=val2的中间状态。不过部分存储引擎(如MySQL InnoDB)会通过行锁机制限制这种场景,让SELECT等待UPDATE释放锁后再读取,但并非所有数据库实现都如此。读已提交(Read Committed)及以上级别:
包括读已提交、可重复读、串行化这几种隔离级别,SELECT只能读到一致性的数据版本:要么是UPDATE执行前的旧值(col1=val1, col2=val2),要么是UPDATE完成并提交后的新值(col1=new_val1, col2=new_val2),绝对不会出现读取部分更新行的情况。
比如MySQL InnoDB默认的可重复读隔离级别,会通过快照读机制让SELECT读取事务启动时的数据快照;如果是需要当前最新数据的当前读(如SELECT ... FOR UPDATE),则会等待UPDATE的行锁释放后,读取完整的更新结果。
总结
只有在读未提交隔离级别下,才存在读取到部分更新行的可能性;在更高的隔离级别中,数据库会通过快照、锁等机制保证查询结果的一致性,不会出现这种情况。
内容的提问来源于stack exchange,提问作者xuhdev

