@@ -462,7 +462,7 @@ UPDATE wiki_pages SET content = '新内容'
462
462
463
463
另一方面,最后写入胜利(LWW)的冲突解决方法很容易丢失更新,如 “[ 最后写入胜利(丢弃并发写入)] ( ch5.md#最后写入胜利(丢弃并发写入) ) ” 中所述。不幸的是,LWW 是许多复制数据库中的默认方案。
464
464
465
- ### 写入偏斜与幻读
465
+ ### 写入偏差与幻读
466
466
467
467
前面的章节中,我们看到了 ** 脏写** 和 ** 丢失更新** ,当不同的事务并发地尝试写入相同的对象时,会出现这两种竞争条件。为了避免数据损坏,这些竞争条件需要被阻止 —— 既可以由数据库自动执行,也可以通过锁和原子写操作这类手动安全措施来防止。
468
468
@@ -478,13 +478,13 @@ UPDATE wiki_pages SET content = '新内容'
478
478
479
479
在两个事务中,应用首先检查是否有两个或以上的医生正在值班;如果是的话,它就假定一名医生可以安全地休班。由于数据库使用快照隔离,两次检查都返回 2 ,所以两个事务都进入下一个阶段。Alice 更新自己的记录休班了,而 Bob 也做了一样的事情。两个事务都成功提交了,现在没有医生值班了。违反了至少有一名医生在值班的要求。
480
480
481
- #### 写偏差的特征
481
+ #### 写入偏差的特征
482
482
483
- 这种异常称为 ** 写偏差 ** 【28】。它既不是 ** 脏写** ,也不是 ** 丢失更新** ,因为这两个事务正在更新两个不同的对象(Alice 和 Bob 各自的待命记录)。在这里发生的冲突并不是那么明显,但是这显然是一个竞争条件:如果两个事务一个接一个地运行,那么第二个医生就不能歇班了。异常行为只有在事务并发进行时才有可能发生。
483
+ 这种异常称为 ** 写入偏差 ** 【28】。它既不是 ** 脏写** ,也不是 ** 丢失更新** ,因为这两个事务正在更新两个不同的对象(Alice 和 Bob 各自的待命记录)。在这里发生的冲突并不是那么明显,但是这显然是一个竞争条件:如果两个事务一个接一个地运行,那么第二个医生就不能歇班了。异常行为只有在事务并发进行时才有可能发生。
484
484
485
485
可以将写入偏差视为丢失更新问题的一般化。如果两个事务读取相同的对象,然后更新其中一些对象(不同的事务可能更新不同的对象),则可能发生写入偏差。在多个事务更新同一个对象的特殊情况下,就会发生脏写或丢失更新(取决于时序)。
486
486
487
- 我们已经看到,有各种不同的方法来防止丢失的更新。但对于写偏差 ,我们的选择更受限制:
487
+ 我们已经看到,有各种不同的方法来防止丢失的更新。但对于写入偏差 ,我们的选择更受限制:
488
488
489
489
* 由于涉及多个对象,单对象的原子操作不起作用。
490
490
* 不幸的是,在一些快照隔离的实现中,自动检测丢失更新对此并没有帮助。在 PostgreSQL 的可重复读,MySQL/InnoDB 的可重复读,Oracle 可串行化或 SQL Server 的快照隔离级别中,都不会自动检测写入偏差【23】。自动防止写入偏差需要真正的可串行化隔离(请参阅 “[ 可串行化] ( #可串行化 ) ”)。
@@ -507,9 +507,9 @@ COMMIT;
507
507
508
508
* 和以前一样,` FOR UPDATE ` 告诉数据库锁定返回的所有行以用于更新。
509
509
510
- #### 写偏差的更多例子
510
+ #### 写入偏差的更多例子
511
511
512
- 写偏差乍看像是一个深奥的问题 ,但一旦意识到这一点,很容易会注意到它可能发生在更多场景下。以下是一些例子:
512
+ 写入偏差乍看像是一个深奥的问题 ,但一旦意识到这一点,很容易会注意到它可能发生在更多场景下。以下是一些例子:
513
513
514
514
* 会议室预订系统
515
515
@@ -771,7 +771,7 @@ WHERE room_id = 123 AND
771
771
772
772
#### 基于过时前提的决策
773
773
774
- 先前讨论了快照隔离中的写入偏差(请参阅 “[ 写入偏斜与幻读 ] ( #写入偏斜与幻读 ) ”)时,我们观察到一个循环模式:事务从数据库读取一些数据,检查查询的结果,并根据它看到的结果决定采取一些操作(写入数据库)。但是,在快照隔离的情况下,原始查询的结果在事务提交时可能不再是最新的,因为数据可能在同一时间被修改。
774
+ 先前讨论了快照隔离中的写入偏差(请参阅 “[ 写入偏差与幻读 ] ( #写入偏差与幻读 ) ”)时,我们观察到一个循环模式:事务从数据库读取一些数据,检查查询的结果,并根据它看到的结果决定采取一些操作(写入数据库)。但是,在快照隔离的情况下,原始查询的结果在事务提交时可能不再是最新的,因为数据可能在同一时间被修改。
775
775
776
776
换句话说,事务基于一个 ** 前提(premise)** 采取行动(事务开始时候的事实,例如:“目前有两名医生正在值班”)。之后当事务要提交时,原始数据可能已经改变 —— 前提可能不再成立。
777
777
@@ -849,7 +849,7 @@ WHERE room_id = 123 AND
849
849
850
850
两个客户端同时执行 ** 读取 - 修改 - 写入序列** 。其中一个写操作,在没有合并另一个写入变更情况下,直接覆盖了另一个写操作的结果。所以导致数据丢失。快照隔离的一些实现可以自动防止这种异常,而另一些实现则需要手动锁定(` SELECT FOR UPDATE ` )。
851
851
852
- * 写偏差
852
+ * 写入偏差
853
853
854
854
一个事务读取一些东西,根据它所看到的值作出决定,并将该决定写入数据库。但是,写入时,该决定的前提不再是真实的。只有可串行化的隔离才能防止这种异常。
855
855
0 commit comments