我正在阅读关于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.在大多数情况下,您还可以获得更好的并发性.