什么是幻读?

参考回答

幻读是指在一个事务中执行两次相同的查询时,结果集的行数不同。通常是因为另一个事务在两次查询之间插入或删除了满足查询条件的数据行,从而导致查询结果的不一致。幻读是事务隔离性问题之一。


详细讲解与拓展

1. 幻读的定义

幻读主要发生在 多行操作 中,例如范围查询(SELECT ... WHERE)。
– 一个事务第一次查询时获取了满足条件的记录。
– 另一个事务在其间插入或删除了符合条件的记录。
– 当第一个事务再次查询时,结果集行数发生了变化,产生“幻影”记录,这就是幻读。

2. 幻读的一个例子

假设有一个商品表 Products

CREATE TABLE Products (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    price DECIMAL(10, 2)
);

-- 初始数据
INSERT INTO Products VALUES (1, 'Product A', 100.00), (2, 'Product B', 200.00);

事务 1

START TRANSACTION;

-- 第一次查询
SELECT * FROM Products WHERE price < 300;  
-- 查询结果:Product A 和 Product B

事务 2(并发执行):

START TRANSACTION;

-- 插入新商品
INSERT INTO Products (id, name, price) VALUES (3, 'Product C', 250.00);

COMMIT;

事务 1(继续执行):

-- 第二次查询
SELECT * FROM Products WHERE price < 300;  
-- 查询结果:Product A、Product B 和 Product C(新增了一行)

事务 1 第一次查询时只有两行记录,但第二次查询时多了一行“幻影”记录(Product C),这就是幻读。


3. 幻读的影响

幻读会导致事务中的数据逻辑不一致,影响业务逻辑,例如:
1. 统计错误:当事务统计某范围内的记录时,新增的记录会导致结果不准确。
2. 业务约束失效:例如,事务需要确保范围内的数据唯一性,但另一事务的插入可能破坏这一约束。


4. 如何防止幻读?

1) 隔离级别与幻读
MySQL 提供的隔离级别对幻读的处理如下:
READ UNCOMMITTED 和 READ COMMITTED:可能发生幻读。
REPEATABLE READ:在 MySQL 中,通过 MVCC(多版本并发控制) 避免了幻读问题。
SERIALIZABLE:通过对查询范围加锁(范围锁),完全防止幻读,但性能较低。

2) 通过 SERIALIZABLE 隔离级别防止幻读
SERIALIZABLE 隔离级别为每个查询加上范围锁(锁住查询范围的所有可能行),确保在事务完成前,其他事务无法插入或删除满足条件的记录。
示例

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT * FROM Products WHERE price < 300 FOR UPDATE;

3) REPEATABLE READ 和 MVCC 的解决方案
MySQL 的 InnoDB 引擎通过 MVCC 的方式,记录事务开始时的数据快照,从而避免幻读问题:
– 每个事务读取的是事务开始时的视图,后续插入的新记录不会影响当前事务的查询结果。


5. 幻读与不可重复读的区别

问题 描述 例子
不可重复读 同一事务中两次读取同一行数据,结果不同,通常是因为另一事务修改了数据。 事务 1 读取 price = 100,事务 2 修改为 price = 200,事务 1 再次读取值变化。
幻读 同一事务中两次范围查询结果的行数不同,通常是因为另一事务插入或删除了数据。 事务 1 查询 price < 300,事务 2 插入一条 price = 250 的记录,事务 1 再次查询多了一行。

6. 幻读的实际应用场景

1) 统计和约束
在电商系统中,当统计商品数量或检测库存时,幻读可能导致统计结果错误或业务逻辑失效。

2) 订单验证
在订单生成过程中,需要确保订单号唯一。如果另一事务插入了同范围内的订单号,可能导致冲突。


总结

幻读是事务隔离性问题之一,发生在范围查询时,另一个事务插入或删除数据导致结果集行数变化。MySQL 的 REPEATABLE READ 隔离级别通过 MVCC 解决了幻读问题,而 SERIALIZABLE 则通过范围锁完全避免幻读。开发者需要根据业务场景选择合适的隔离级别,以在性能和一致性之间找到平衡。

发表评论

后才能评论