mysql – InnoDB和隔离级别 – 不可重复读取不好的东西?

我正在阅读关于InnoDB的isolation levels,它在很大程度上是有道理的,但我不知道的是为什么不可重复的读取是一件坏事?不应该是相反的方式吗?

举些例子:

所以说我们有一个用于销售产品的库存列,每次有人购买了一个项目,我们会从列中获取1个项目,可重复读取或可序列化的隔离级别不会破坏数据完整性吗?

例如:

TX A: start transaction;
TX B: set session transaction isolation level repeatable read;
TX B: start transaction;
TX A: select stock from products;               -- val = 8
TX B: select stock from products;               -- val = 8
TX A: update products set stock = stock - 1;    -- val = 7
TX B: select stock from products;               -- val = 8
TX A: commit
TX B: select stock from products;               -- val = 8, incorrect!
TX B: commit;
TX B: select stock from products;               -- val = 7

除非它在运行更新时使用CORRECT值?

解决方法:

InnoDB隔离级别不是“坏”或“好”,它取决于您的应用程序在隔离方面需要什么.

在您的示例中,通过使用可重复读取,您确保在完成第一个选择后,从该事务的角度来看,没有其他事务可以修改数据库的状态.换句话说,就好像你在第5行之前运行了“开始交易以及一致的快照”.在某些情况下可能需要这样做,让我举个例子:

TX A: START TRANSACTION;
TX A: SELECT * FROM products WHERE stock BETWEEN 4 AND 6; -- I see rows 4 and 6 only,
                                                          --  and I want to update those only   
TX B: START TRANSACTION;
TX B: INSERT INTO products (stock) VALUES (5);

TX A: UPDATE products SET stock = 3 WHERE stock BETWEEN 4 AND 6;
TX A: COMMIT; -- race condition
TX B: COMMIT;

通过设置InnoDB的REPEATABLE READ,幻像读取消失,因为TX B将被锁定在插入,直到A提交.但是,如果我们正在执行READ COMMITTED,我们将获得不同的输出,具体取决于A或B是否首先提交,违反ACID属性的东西,以及我们的应用程序可能没有预料到的.

特别是,基于STATEMENT的复制不需要幻像读取,这就是为什么READ COMMITTED是默认级别,并且甚至比其他数据库中的READ COMMITTED具有更严格的行为(需要序列化才能获得InnoDB行为).如果第一个选择是更新,则独立执行这些事务将导致不同的结果(漂移从属).请注意,事务以原子方式和串行方式写入binlog.

我同意你的意见,大多数应用程序可能不需要,因为你将在应用程序级别处理这些情况.如果是这种情况,请使用基于ROW的复制并将默认事务隔离级别设置为READ COMMITTED.在大多数情况下,您还可以获得更好的并发性.

上一篇:mysql – 空闲连接加上模式修改查询导致锁定数据库


下一篇:MySQL:事务会锁定行吗?