理解 MySQL 中的脏读、不可重复读、幻读及其事务隔离级别

发布时间:2026/8/28 13:25:35
理解 MySQL 中的脏读、不可重复读、幻读及其事务隔离级别 在数据库系统中事务Transaction是一个不可分割的操作序列。为了保证数据的一致性和完整性数据库系统提供了事务的隔离机制也就是ACID中的I。根据 SQL 标准事务隔离级别分为四种READ UNCOMMITTED读未提交、READ COMMITTED读已提交、REPEATABLE READ可重复读和SERIALIZABLE可串行化。不同的隔离级别可以避免不同类型的数据不一致问题脏读、不可重复读、幻读。1. 脏读Dirty Read脏读是指一个事务能够读取到另一个事务未提交的数据。这可能导致一个事务读取到的数据是临时的、不正确的。示例假设有一张accounts表用于存储用户的账户信息。CREATETABLEaccounts(idINTPRIMARYKEY,nameVARCHAR(50),balanceDECIMAL(10,2));当前表中的数据如下idnamebalance1Alice1000.00事务 A开始并更新Alice的账户余额STARTTRANSACTION;UPDATEaccountsSETbalance1500.00WHEREid1;此时事务 A 尚未提交事务 B开始并读取Alice的账户余额STARTTRANSACTION;SELECTbalanceFROMaccountsWHEREid1;在READ UNCOMMITTED隔离级别下事务 B 读取到的余额为1500.00即事务 A 尚未提交的修改。假设事务 A 随后回滚ROLLBACK;此时事务 B 读取到的数据实际上是错误的因为事务 A 已回滚Alice的余额仍然是1000.00。避免脏读设置隔离级别为READ COMMITTED或更高确保事务只能读取到已提交的数据。2. 不可重复读Non-Repeatable Read不可重复读发生在同一个事务中读取同一条记录两次时由于另一个事务对该记录进行了更新导致两次读取的结果不一致。示例事务 A开始并读取Alice的账户余额STARTTRANSACTION;SELECTbalanceFROMaccountsWHEREid1;第一次查询结果为1000.00。事务 B更新了Alice的账户余额STARTTRANSACTION;UPDATEaccountsSETbalance1500.00WHEREid1;COMMIT;事务 A再次读取Alice的账户余额SELECTbalanceFROMaccountsWHEREid1;这次查询结果变为1500.00与第一次查询结果不一致导致不可重复读。避免不可重复读设置隔离级别为REPEATABLE READ或SERIALIZABLE确保同一事务中对同一记录的读取结果一致。3. 幻读Phantom Read幻读发生在一个事务中读取同一范围的记录两次时由于另一个事务插入或删除了数据导致两次读取的结果不一致。幻读与不可重复读的区别在于幻读是针对数据集范围的变化而不可重复读是针对单条记录的变化。示例假设有一张orders表存储用户的订单信息。CREATETABLEorders(idINTPRIMARYKEY,user_idINT,amountDECIMAL(10,2));当前表中的数据如下iduser_idamount11200.0021150.0032300.0041500.0052400.00事务 A开始并读取用户user_id 1的所有订单STARTTRANSACTION;SELECT*FROMordersWHEREuser_id1;第一次查询结果为iduser_idamount11200.0021150.0041500.00事务 B插入一条新订单STARTTRANSACTION;INSERTINTOorders(id,user_id,amount)VALUES(6,1,100.00);COMMIT;事务 A再次读取用户user_id 1的订单SELECT*FROMordersWHEREuser_id1;这次查询结果为iduser_idamount11200.0021150.0041500.0061100.00事务 A 发现比第一次查询多了一条记录这就是幻读。避免幻读设置隔离级别为SERIALIZABLE在这种隔离级别下事务会对读取的数据集加锁防止其他事务插入或删除记录。4. 事务隔离级别MySQL 提供了四种事务隔离级别来控制不同类型的数据不一致问题READ UNCOMMITTED最低的隔离级别允许脏读、不可重复读和幻读的发生。READ COMMITTED允许不可重复读和幻读的发生避免脏读。大多数数据库默认的隔离级别。REPEATABLE READ避免脏读和不可重复读但可能会发生幻读。MySQL 的默认隔离级别。SERIALIZABLE最高的隔离级别避免脏读、不可重复读和幻读但性能开销最大。结语选择合适的事务隔离级别对应用程序的性能和数据一致性至关重要。在设计数据库事务时需要根据业务需求权衡不同类型的数据不一致问题以及它们对系统性能的影响。通过理解和合理运用这些隔离级别可以有效避免脏读、不可重复读和幻读从而保障数据的正确性和系统的稳定性。