InnoDB 和隔离级别 - 可重复读取不是一件坏事吗?

Bre*_*ett 4 mysql innodb locking isolation-level

我正在阅读有关InnoDB's 隔离级别的内容,这在很大程度上是有道理的,但我不明白为什么是unrepeatable reads一件坏事?不应该反过来吗?

举些例子:

因此,假设我们有一个用于销售产品的库存列,每次有人购买一件商品时,我们都会从该列中取出 1 件商品,使用Repeatable readserializable隔离级别会不会破坏数据完整性?

例如:

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
Run Code Online (Sandbox Code Playgroud)

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

jyn*_*nus 5

InnoDB 隔离级别没有“坏”或“好”之分,这取决于您的应用程序在隔离方面的要求。

在您的示例中,通过使用可重复读取,您可以确保在完成第一个选择后,从该事务的角度来看,没有其他事务可以修改数据库的状态。换句话说,就好像您START TRANSACTION WITH CONSISTENT SNAPSHOT在第 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;
Run Code Online (Sandbox Code Playgroud)

通过设置 InnoDB's REPEATABLE READ,幻读消失,因为 TX B 将在插入时被锁定,直到 A 提交。然而,如果我们正在做READ COMMITTED,我们会得到不同的输出,这取决于 A 还是 B 先提交,这违反了 ACID 属性,并且我们的应用程序可能不会预料到。

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

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