读写偏斜现象的初学者指南
介紹
在關于ACID和數據庫事務的文章中,我介紹了SQL標準描述的三種現象:
- 臟讀
- 不可重復讀
- 幻讀
盡管這些可以很好地區分四個隔離級別(未提交讀,已提交讀,可重復讀和可序列化),但實際上,還有更多的現象需要考慮。 1995年的論文(《 ANSI SQL隔離級別批判》)介紹了標準規范中省略的其他現象。
在我的《高性能Java持久性》一書中,我決定堅持“事務”一章,因為它對數據訪問的有效性和效率都非常重要。
領域模型
對于以下示例,我將使用以下兩個實體:
在我們的虛構應用程序中,更改“ 帖子”標題后,必須將作者記錄在關聯的“ PostDetails”記錄中。 如果未防止讀寫時滯,則可以破壞此域模型約束,如以下測試案例所示。
讀取歪斜
以下測試模擬了讀取偏斜如何發生:
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()); });- 愛麗絲選擇一個帖子標題
- Bob潛入并更新了Post和PostDetails實體
- Alice線程將繼續,并且她選擇PostDetails記錄
如果允許讀取偏斜,則Alice會看到Bob的更新,并且可以假定先前的Post版本(在交易開始時讀取)是Bob發行的(可能不準確)。
在四個最常見的關系數據庫系統上運行此測試可獲得以下結果:
| Oracle讀已提交 | 是 |
| Oracle可序列化 | 沒有 |
| SQL Server讀未提交 | 是 |
| SQL Server讀取已提交 | 是 |
| SQL Server讀取提交的快照隔離 | 是 |
| SQL Server可重復讀取 | 沒有 |
| SQL Server可序列化 | 沒有 |
| SQL Server快照隔離 | 沒有 |
| PostgreSQL讀未提交 | 是 |
| PostgreSQL讀已提交 | 是 |
| PostgreSQL可重復讀 | 沒有 |
| PostgreSQL可序列化 | 沒有 |
| MySQL讀取未提交 | 是 |
| MySQL讀取提交 | 是 |
| MySQL可重復讀 | 沒有 |
| MySQL可序列化 | 沒有 |
寫偏斜
要模擬寫偏斜,您需要執行以下測試用例:
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標題和作者
- Bob還選擇了Post標題和相關的作者,但他決定僅更新標題
- 愛麗絲想在不更改帖子標題的情況下更新PostDetails記錄
如果允許寫偏斜,則將執行Alice和Bob不相交的寫操作,而不會受到控制這兩個記錄的約束的阻止。
在四個最常見的關系數據庫系統上運行此測試可獲得以下結果:
| Oracle讀已提交 | 是 |
| Oracle可序列化 | 是 |
| SQL Server讀未提交 | 是 |
| SQL Server讀取已提交 | 是 |
| SQL Server讀取提交的快照隔離 | 是 |
| SQL Server可重復讀取 | 沒有 |
| SQL Server可序列化 | 沒有 |
| SQL Server快照隔離 | 是 |
| PostgreSQL讀未提交 | 是 |
| PostgreSQL讀已提交 | 是 |
| PostgreSQL可重復讀 | 是 |
| PostgreSQL可序列化 | 沒有 |
| MySQL讀取未提交 | 是 |
| MySQL讀取提交 | 是 |
| MySQL可重復讀 | 是 |
| MySQL可序列化 | 沒有 |
- 寫偏斜在多版本并發控制機制中很普遍,即使聲稱使用“可序列化”,Oracle也無法阻止它,而實際上它只是一個快照隔離級別。
- 當使用“可重復讀”和“可序列化”時,SQL Server默認的基于鎖定的隔離級別可以防止寫偏斜。 快照隔離級別(基于MVCC)中的任何一個都不能阻止/檢測到它。
- PostgreSQL使用更高級的可序列化快照隔離級別來阻止它
- MySQL在使用Serializable時會使用共享鎖,因此即使InnoDB也是基于MVCC的,也可以防止寫偏斜
如果您對此主題感興趣,那么您也可以閱讀我正在編寫的《 高性能Java持久性》一書。
翻譯自: https://www.javacodegeeks.com/2015/10/a-beginners-guide-to-read-and-write-skew-phenomena.html
總結
以上是生活随笔為你收集整理的读写偏斜现象的初学者指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: caj论文阅读神器
- 下一篇: H5页面前端开发常见的兼容性问题解决方法