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