mirror of
https://github.com/Vonng/ddia.git
synced 2024-12-06 15:20:12 +08:00
Merge branch 'master' into ch7
This commit is contained in:
commit
663d64030d
@ -150,6 +150,7 @@
|
||||
|
||||
| ISSUE & Pull Requests | USER | Title |
|
||||
| ----------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| [253](https://github.com/Vonng/ddia/pull/253) | [@AlphaWang](https://github.com/AlphaWang) | ch7: 修正“读已提交”相关内容的多处翻译不当 |
|
||||
| [246](https://github.com/Vonng/ddia/pull/246) | [@derekwu0101](https://github.com/derekwu0101) | ch3: 修正繁体中文的转译错误 |
|
||||
| [245](https://github.com/Vonng/ddia/pull/245) | [@skyran1278](https://github.com/skyran1278) | ch12: 修正繁体中文的转译错误 |
|
||||
| [244](https://github.com/Vonng/ddia/pull/244) | [@Axlgrep](https://github.com/Axlgrep) | ch9: 修正不通顺的翻译 |
|
||||
|
@ -150,6 +150,7 @@
|
||||
|
||||
| ISSUE & Pull Requests | USER | Title |
|
||||
| ----------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| [253](https://github.com/Vonng/ddia/pull/253) | [@AlphaWang](https://github.com/AlphaWang) | ch7: 修正“讀已提交”相關內容的多處翻譯不當 |
|
||||
| [246](https://github.com/Vonng/ddia/pull/246) | [@derekwu0101](https://github.com/derekwu0101) | ch3: 修正繁體中文的轉譯錯誤 |
|
||||
| [245](https://github.com/Vonng/ddia/pull/245) | [@skyran1278](https://github.com/skyran1278) | ch12: 修正繁體中文的轉譯錯誤 |
|
||||
| [244](https://github.com/Vonng/ddia/pull/244) | [@Axlgrep](https://github.com/Axlgrep) | ch9: 修正不通順的翻譯 |
|
||||
|
10
zh-tw/ch7.md
10
zh-tw/ch7.md
@ -233,7 +233,7 @@ SELECT COUNT(*)FROM emails WHERE recipient_id = 2 AND unread_flag = true
|
||||
最基本的事務隔離級別是 **讀已提交(Read Committed)**[^v],它提供了兩個保證:
|
||||
|
||||
1. 從資料庫讀時,只能看到已提交的資料(沒有 **髒讀**,即 dirty reads)。
|
||||
2. 寫入資料庫時,只會覆蓋已經寫入的資料(沒有 **髒寫**,即 dirty writes)。
|
||||
2. 寫入資料庫時,只會覆蓋已經提交的資料(沒有 **髒寫**,即 dirty writes)。
|
||||
|
||||
我們來更詳細地討論這兩個保證。
|
||||
|
||||
@ -262,7 +262,7 @@ SELECT COUNT(*)FROM emails WHERE recipient_id = 2 AND unread_flag = true
|
||||
|
||||
透過防止髒寫,這個隔離級別避免了一些併發問題:
|
||||
|
||||
- 如果事務更新多個物件,髒寫會導致不好的結果。例如,考慮 [圖 7-5](../img/fig7-5.png),以一個二手車銷售網站為例,Alice 和 Bob 兩個人同時試圖購買同一輛車。購買汽車需要兩次資料庫寫入:網站上的商品列表需要更新,以反映買家的購買,銷售發票需要傳送給買家。在 [圖 7-5](../img/fig7-5.png) 的情況下,銷售是屬於 Bob 的(因為他成功更新了商品列表),但發票卻寄送給了愛麗絲(因為她成功更新了發票表)。讀已提交會阻止這樣的事故。
|
||||
- 如果事務更新多個物件,髒寫會導致不好的結果。例如,考慮 [圖 7-5](../img/fig7-5.png),以一個二手車銷售網站為例,Alice 和 Bob 兩個人同時試圖購買同一輛車。購買汽車需要兩次資料庫寫入:網站上的商品列表需要更新,以反映買家的購買,銷售發票需要傳送給買家。在 [圖 7-5](../img/fig7-5.png) 的情況下,銷售是屬於 Bob 的(因為他成功更新了商品列表),但發票卻寄送給了 Alice(因為她成功更新了發票表)。讀已提交會防止這樣的事故。
|
||||
- 但是,讀已提交併不能防止 [圖 7-1](../img/fig7-1.png) 中兩個計數器增量之間的競爭狀態。在這種情況下,第二次寫入發生在第一個事務提交後,所以它不是一個髒寫。這仍然是不正確的,但是出於不同的原因,在 “[防止更新丟失](#防止丟失更新)” 中將討論如何使這種計數器增量安全。
|
||||
|
||||
![](../img/fig7-5.png)
|
||||
@ -275,13 +275,13 @@ SELECT COUNT(*)FROM emails WHERE recipient_id = 2 AND unread_flag = true
|
||||
|
||||
最常見的情況是,資料庫透過使用 **行鎖(row-level lock)** 來防止髒寫:當事務想要修改特定物件(行或文件)時,它必須首先獲得該物件的鎖。然後必須持有該鎖直到事務被提交或中止。一次只有一個事務可持有任何給定物件的鎖;如果另一個事務要寫入同一個物件,則必須等到第一個事務提交或中止後,才能獲取該鎖並繼續。這種鎖定是讀已提交模式(或更強的隔離級別)的資料庫自動完成的。
|
||||
|
||||
如何防止髒讀?一種選擇是使用相同的鎖,並要求任何想要讀取物件的事務來簡單地獲取該鎖,然後在讀取之後立即再次釋放該鎖。這將確保在物件具有髒的、未提交的值時不會發生讀取(因為在此期間,鎖將由進行寫入的事務持有)。
|
||||
如何防止髒讀?一種選擇是使用相同的鎖,並要求任何想要讀取物件的事務來簡單地獲取該鎖,然後在讀取之後立即再次釋放該鎖。這將確保在物件具有髒的、未提交的值時不會發生讀取(因為在此期間,鎖將由進行寫入的事務持有)。
|
||||
|
||||
但是要求讀鎖的辦法在實踐中效果並不好。因為一個長時間執行的寫入事務會迫使許多隻讀事務等到這個慢寫入事務完成。這會損失只讀事務的響應時間,並且不利於可操作性:因為等待鎖,應用某個部分的遲緩可能由於連鎖效應,導致其他部分出現問題。
|
||||
但是要求讀鎖的辦法在實踐中效果並不好。因為一個長時間執行的寫入事務會迫使許多隻讀事務等到這個慢寫入事務完成。這會影響只讀事務的響應時間,並且不利於可操作性:因為等待鎖,應用某個部分的遲緩可能由於連鎖效應,導致其他部分出現問題。
|
||||
|
||||
出於這個原因,大多數資料庫 [^vi] 使用 [圖 7-4](../img/fig7-4.png) 的方式防止髒讀:對於寫入的每個物件,資料庫都會記住舊的已提交值,和由當前持有寫入鎖的事務設定的新值。當事務正在進行時,任何其他讀取物件的事務都會拿到舊值。 只有當新值提交後,事務才會切換到讀取新值。
|
||||
|
||||
[^vi]: 在撰寫本文時,唯一在讀已提交隔離級別使用讀鎖的主流資料庫是使用 `read_committed_snapshot = off` 配置的 IBM DB2 和 Microsoft SQL Server 【23,36】。
|
||||
[^vi]: 在撰寫本文時,唯一在讀已提交隔離級別使用讀鎖的主流資料庫是 IBM DB2 和使用 `read_committed_snapshot = off` 配置的 Microsoft SQL Server【23,36】。
|
||||
|
||||
### 快照隔離和可重複讀
|
||||
|
||||
|
@ -165,7 +165,7 @@
|
||||
|
||||
唯一性約束在資料庫中很常見:例如,使用者名稱或電子郵件地址必須唯一標識一個使用者,而在檔案儲存服務中,不能有兩個具有相同路徑和檔名的檔案。如果要在寫入資料時強制執行此約束(例如,如果兩個人試圖同時建立一個具有相同名稱的使用者或檔案,其中一個將返回一個錯誤),則需要線性一致性。
|
||||
|
||||
這種情況實際上類似於一個鎖:當一個使用者註冊你的服務時,可以認為他們獲得了所選使用者名稱的 “鎖定”。該操作與原子性的比較與設定(CAS)非常相似:將使用者名稱賦予宣告它的使用者,前提是使用者名稱尚未被使用。
|
||||
這種情況實際上類似於一個鎖:當一個使用者註冊你的服務時,可以認為他們獲得了所選使用者名稱的 “鎖”。該操作與原子性的比較與設定(CAS)非常相似:將使用者名稱賦予宣告它的使用者,前提是使用者名稱尚未被使用。
|
||||
|
||||
如果想要確保銀行賬戶餘額永遠不會為負數,或者不會出售比倉庫裡的庫存更多的物品,或者兩個人不會都預定了航班或劇院裡同一時間的同一個位置。這些約束條件都要求所有節點都同意一個最新的值(賬戶餘額,庫存水平,座位佔用率)。
|
||||
|
||||
@ -256,7 +256,7 @@
|
||||
|
||||
在單主配置的條件下,如果資料中心之間的網路被中斷,則連線到從庫資料中心的客戶端無法聯絡到主庫,因此它們無法對資料庫執行任何寫入,也不能執行任何線性一致的讀取。它們仍能從從庫讀取,但結果可能是陳舊的(非線性一致)。如果應用需要線性一致的讀寫,卻又位於與主庫網路中斷的資料中心,則網路中斷將導致這些應用不可用。
|
||||
|
||||
如果客戶端可以直接連線到主庫所在的資料中心,這就不是問題了,那些應用可以繼續正常工作。但只能訪問從庫資料中心的客戶端會中斷執行,直到網路連結得到修復。
|
||||
如果客戶端可以直接連線到主庫所在的資料中心,這就不是問題了,那些應用可以繼續正常工作。但只能訪問從庫資料中心的客戶端會中斷執行,直到網路連線得到修復。
|
||||
|
||||
#### CAP定理
|
||||
|
||||
@ -527,7 +527,7 @@ CAP 定理的正式定義僅限於很狹隘的範圍【30】,它只考慮了
|
||||
|
||||
實現一個帶有原子性 **自增並返回** 操作的線性一致暫存器有多困難?像往常一樣,如果事情從來不出差錯,那很容易:你可以簡單地把它儲存在單個節點內的變數中。問題在於處理當該節點的網路連線中斷時的情況,並在該節點失效時能恢復這個值【59】。一般來說,如果你對線性一致性的序列號生成器進行過足夠深入的思考,你不可避免地會得出一個共識演算法。
|
||||
|
||||
這並非巧合:可以證明,線性一致的 CAS(或自增並返回)暫存器與全序廣播都都等價於 **共識** 問題【28,67】。也就是說,如果你能解決其中的一個問題,你可以把它轉化成為其他問題的解決方案。這是相當深刻和令人驚訝的洞察!
|
||||
這並非巧合:可以證明,線性一致的 CAS(或自增並返回)暫存器與全序廣播都等價於 **共識** 問題【28,67】。也就是說,如果你能解決其中的一個問題,你可以把它轉化成為其他問題的解決方案。這是相當深刻和令人驚訝的洞察!
|
||||
|
||||
現在是時候正面處理共識問題了,我們將在本章的其餘部分進行討論。
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user