读写偏斜现象的初学者指南
介紹
在關(guān)于ACID和數(shù)據(jù)庫事務(wù)的文章中,我介紹了SQL標(biāo)準(zhǔn)描述的三種現(xiàn)象:
- 臟讀
- 不可重復(fù)讀
- 幻讀
盡管這些可以很好地區(qū)分四個(gè)隔離級(jí)別(未提交讀,已提交讀,可重復(fù)讀和可序列化),但實(shí)際上,還有更多的現(xiàn)象需要考慮。 1995年的論文(《 ANSI SQL隔離級(jí)別批判》)介紹了標(biāo)準(zhǔn)規(guī)范中省略的其他現(xiàn)象。
在我的《高性能Java持久性》一書中,我決定堅(jiān)持“事務(wù)”一章,因?yàn)樗鼘?shù)據(jù)訪問的有效性和效率都非常重要。
領(lǐng)域模型
對于以下示例,我將使用以下兩個(gè)實(shí)體:
在我們的虛構(gòu)應(yīng)用程序中,更改“ 帖子”標(biāo)題后,必須將作者記錄在關(guān)聯(lián)的“ PostDetails”記錄中。 如果未防止讀寫時(shí)滯,則可以破壞此域模型約束,如以下測試案例所示。
讀取歪斜
以下測試模擬了讀取偏斜如何發(fā)生:
doInConnection(aliceConnection -> {prepareConnection(aliceConnection);String title = selectStringColumn(aliceConnection, selectPostTitleSql());executeSync(() -> {doInConnection(bobConnection -> {prepareConnection(bobConnection);try {update(bobConnection, updatePostTitleParamSql(), new Object[]{"Bob"});update(bobConnection, updatePostDetailsAuthorParamSql(), new Object[]{"Bob"});} catch (Exception e) {LOGGER.info("Exception thrown", e);preventedByLocking.set(true);}});});String createdBy = selectStringColumn(aliceConnection, selectPostDetailsAuthorSql()); });- 愛麗絲選擇一個(gè)帖子標(biāo)題
- Bob潛入并更新了Post和PostDetails實(shí)體
- Alice線程將繼續(xù),并且她選擇PostDetails記錄
如果允許讀取偏斜,則Alice會(huì)看到Bob的更新,并且可以假定先前的Post版本(在交易開始時(shí)讀取)是Bob發(fā)行的(可能不準(zhǔn)確)。
在四個(gè)最常見的關(guān)系數(shù)據(jù)庫系統(tǒng)上運(yùn)行此測試可獲得以下結(jié)果:
| Oracle讀已提交 | 是 |
| Oracle可序列化 | 沒有 |
| SQL Server讀未提交 | 是 |
| SQL Server讀取已提交 | 是 |
| SQL Server讀取提交的快照隔離 | 是 |
| SQL Server可重復(fù)讀取 | 沒有 |
| SQL Server可序列化 | 沒有 |
| SQL Server快照隔離 | 沒有 |
| PostgreSQL讀未提交 | 是 |
| PostgreSQL讀已提交 | 是 |
| PostgreSQL可重復(fù)讀 | 沒有 |
| PostgreSQL可序列化 | 沒有 |
| MySQL讀取未提交 | 是 |
| MySQL讀取提交 | 是 |
| MySQL可重復(fù)讀 | 沒有 |
| MySQL可序列化 | 沒有 |
寫偏斜
要模擬寫偏斜,您需要執(zhí)行以下測試用例:
doInConnection(aliceConnection -> {prepareConnection(aliceConnection);String title = selectStringColumn(aliceConnection, selectPostTitleSql());String createdBy = selectStringColumn(aliceConnection, selectPostDetailsAuthorSql());executeSync(() -> {doInConnection(bobConnection -> {prepareConnection(bobConnection);try {String bobTitle = selectStringColumn(bobConnection, selectPostTitleSql());String bonCreatedBy = selectStringColumn(bobConnection, selectPostDetailsAuthorSql());update(bobConnection, updatePostTitleParamSql(), new Object[]{"Bob"});} catch (Exception e) {LOGGER.info("Exception thrown", e);preventedByLocking.set(true);}});});update(aliceConnection, updatePostDetailsAuthorParamSql(), new Object[]{"Alice"}); });- 愛麗絲從PostDetails記錄中選擇Post標(biāo)題和作者
- Bob還選擇了Post標(biāo)題和相關(guān)的作者,但他決定僅更新標(biāo)題
- 愛麗絲想在不更改帖子標(biāo)題的情況下更新PostDetails記錄
如果允許寫偏斜,則將執(zhí)行Alice和Bob不相交的寫操作,而不會(huì)受到控制這兩個(gè)記錄的約束的阻止。
在四個(gè)最常見的關(guān)系數(shù)據(jù)庫系統(tǒng)上運(yùn)行此測試可獲得以下結(jié)果:
| Oracle讀已提交 | 是 |
| Oracle可序列化 | 是 |
| SQL Server讀未提交 | 是 |
| SQL Server讀取已提交 | 是 |
| SQL Server讀取提交的快照隔離 | 是 |
| SQL Server可重復(fù)讀取 | 沒有 |
| SQL Server可序列化 | 沒有 |
| SQL Server快照隔離 | 是 |
| PostgreSQL讀未提交 | 是 |
| PostgreSQL讀已提交 | 是 |
| PostgreSQL可重復(fù)讀 | 是 |
| PostgreSQL可序列化 | 沒有 |
| MySQL讀取未提交 | 是 |
| MySQL讀取提交 | 是 |
| MySQL可重復(fù)讀 | 是 |
| MySQL可序列化 | 沒有 |
- 寫偏斜在多版本并發(fā)控制機(jī)制中很普遍,即使聲稱使用“可序列化”,Oracle也無法阻止它,而實(shí)際上它只是一個(gè)快照隔離級(jí)別。
- 當(dāng)使用“可重復(fù)讀”和“可序列化”時(shí),SQL Server默認(rèn)的基于鎖定的隔離級(jí)別可以防止寫偏斜。 快照隔離級(jí)別(基于MVCC)中的任何一個(gè)都不能阻止/檢測到它。
- PostgreSQL使用更高級(jí)的可序列化快照隔離級(jí)別來阻止它
- MySQL在使用Serializable時(shí)會(huì)使用共享鎖,因此即使InnoDB也是基于MVCC的,也可以防止寫偏斜
如果您對此主題感興趣,那么您也可以閱讀我正在編寫的《 高性能Java持久性》一書。
翻譯自: https://www.javacodegeeks.com/2015/10/a-beginners-guide-to-read-and-write-skew-phenomena.html
總結(jié)
以上是生活随笔為你收集整理的读写偏斜现象的初学者指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: caj论文阅读神器
- 下一篇: 印度软件和中国软件工程师_如何成为印度的