mongodb使用find查詢傳回的遊標,是否可以遍歷出查詢執行後(記錄比較多查詢時間比較長,此時查詢還未執行完)資料表新增的記錄。 例如: 線程A在時間點t1使用find查詢資料表user傳回遊標,遍歷資料記錄。 線程B在時間點t2使用insert向資料表user插入記錄。 線程B在時間點t3執行完成。 線程A在時間點t4執行完成。 時間:t1 < t2 < t3 < t4 問:線程A是否可以查詢到線程B新增的記錄?
這是個非常好的問題,簡單說 MongoDB 不保證結果是否包含新文檔,因為它涉及多個文檔,甚至包括未來可能插入的文檔。在傳統資料庫中,可能讀到新插入的值,這一異常情況被稱為Phantom (幽靈),能滿足這一點的isolation (隔離、獨立) 等級是最高的serializable (可串行化),就是說例子中的一讀一寫兩組操作看起來好像是一先一後。用鎖機制實現的代價也非常高,效能也就比較差。參見這一論文。回到 MongoDB, MongoDB 以文件為單元,能夠保證文件層級的隔離,但是不保證多文檔間的作業的隔離(獨立),也就不支援事務,換來的是高效能。
@huandu 說的沒錯,你測試時用 find().batchSize(2) 改成每批讀2個文檔,就會發現是可以讀到新加入的文檔的。預設的 batchSize 在 shell 裡是 20,可能就不容易觀察到了。別用 batchSize(1), 因為歷史原因它等於limit()。
find().batchSize(2)
不一定。
mongodb cursor 沒有隔離,可能會傳回更新後的資料。
不過實際嘗試過程中發現,無論如何 insert,cursor 始終無法傳回新插入的資料。這可能是 mongodb 的實作細節,也可能在某些特殊情況下 cursor 才可以存取到新 insert 的數據,總之沒有文檔支持,不應該依賴這個行為。
這是個非常好的問題,簡單說 MongoDB 不保證結果是否包含新文檔,因為它涉及多個文檔,甚至包括未來可能插入的文檔。在傳統資料庫中,可能讀到新插入的值,這一異常情況被稱為Phantom (幽靈),能滿足這一點的isolation (隔離、獨立) 等級是最高的serializable (可串行化),就是說例子中的一讀一寫兩組操作看起來好像是一先一後。用鎖機制實現的代價也非常高,效能也就比較差。參見這一論文。回到 MongoDB, MongoDB 以文件為單元,能夠保證文件層級的隔離,但是不保證多文檔間的作業的隔離(獨立),也就不支援事務,換來的是高效能。
@huandu 說的沒錯,你測試時用
find().batchSize(2)
改成每批讀2個文檔,就會發現是可以讀到新加入的文檔的。預設的 batchSize 在 shell 裡是 20,可能就不容易觀察到了。別用 batchSize(1), 因為歷史原因它等於limit()。不一定。
mongodb cursor 沒有隔離,可能會傳回更新後的資料。
不過實際嘗試過程中發現,無論如何 insert,cursor 始終無法傳回新插入的資料。這可能是 mongodb 的實作細節,也可能在某些特殊情況下 cursor 才可以存取到新 insert 的數據,總之沒有文檔支持,不應該依賴這個行為。