Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] ch7 术语统一,写入偏斜->写入偏差,写偏差->写入偏差 #273

Merged
merged 1 commit into from
Oct 29, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions ch7.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ UPDATE wiki_pages SET content = '新内容'

另一方面,最后写入胜利(LWW)的冲突解决方法很容易丢失更新,如 “[最后写入胜利(丢弃并发写入)](ch5.md#最后写入胜利(丢弃并发写入))” 中所述。不幸的是,LWW 是许多复制数据库中的默认方案。

### 写入偏斜与幻读
### 写入偏差与幻读

前面的章节中,我们看到了 **脏写** 和 **丢失更新**,当不同的事务并发地尝试写入相同的对象时,会出现这两种竞争条件。为了避免数据损坏,这些竞争条件需要被阻止 —— 既可以由数据库自动执行,也可以通过锁和原子写操作这类手动安全措施来防止。

Expand All @@ -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】。自动防止写入偏差需要真正的可串行化隔离(请参阅 “[可串行化](#可串行化)”)。
Expand All @@ -507,9 +507,9 @@ COMMIT;

* 和以前一样,`FOR UPDATE` 告诉数据库锁定返回的所有行以用于更新。

#### 写偏差的更多例子
#### 写入偏差的更多例子

写偏差乍看像是一个深奥的问题,但一旦意识到这一点,很容易会注意到它可能发生在更多场景下。以下是一些例子:
写入偏差乍看像是一个深奥的问题,但一旦意识到这一点,很容易会注意到它可能发生在更多场景下。以下是一些例子:

* 会议室预订系统

Expand Down Expand Up @@ -771,7 +771,7 @@ WHERE room_id = 123 AND

#### 基于过时前提的决策

先前讨论了快照隔离中的写入偏差(请参阅 “[写入偏斜与幻读](#写入偏斜与幻读)”)时,我们观察到一个循环模式:事务从数据库读取一些数据,检查查询的结果,并根据它看到的结果决定采取一些操作(写入数据库)。但是,在快照隔离的情况下,原始查询的结果在事务提交时可能不再是最新的,因为数据可能在同一时间被修改。
先前讨论了快照隔离中的写入偏差(请参阅 “[写入偏差与幻读](#写入偏差与幻读)”)时,我们观察到一个循环模式:事务从数据库读取一些数据,检查查询的结果,并根据它看到的结果决定采取一些操作(写入数据库)。但是,在快照隔离的情况下,原始查询的结果在事务提交时可能不再是最新的,因为数据可能在同一时间被修改。

换句话说,事务基于一个 **前提(premise)** 采取行动(事务开始时候的事实,例如:“目前有两名医生正在值班”)。之后当事务要提交时,原始数据可能已经改变 —— 前提可能不再成立。

Expand Down Expand Up @@ -849,7 +849,7 @@ WHERE room_id = 123 AND

两个客户端同时执行 **读取 - 修改 - 写入序列**。其中一个写操作,在没有合并另一个写入变更情况下,直接覆盖了另一个写操作的结果。所以导致数据丢失。快照隔离的一些实现可以自动防止这种异常,而另一些实现则需要手动锁定(`SELECT FOR UPDATE`)。

* 写偏差
* 写入偏差

一个事务读取一些东西,根据它所看到的值作出决定,并将该决定写入数据库。但是,写入时,该决定的前提不再是真实的。只有可串行化的隔离才能防止这种异常。

Expand Down