?
本文檔使用
php中文網(wǎng)手冊 發(fā)布
因為不管哪種隔離級別,對PostgreSQL的讀動作都不會鎖定數(shù)據(jù),所以一個事務(wù)讀取的數(shù)據(jù)可能被另一個事務(wù)覆蓋。 換句話說,如果一條SELECT返回了一行,這并不意味著在返回該行時該行還存在, 也就是說在語句完成或事務(wù)開始后的某時該行可能已經(jīng)被一個在此事務(wù)開始之后提交的事務(wù)更新或者刪除。 即使該行"現(xiàn)在"仍然有效,它也可能在當(dāng)前事務(wù)提交或者回滾之前被改變或者刪除。
另外一個認(rèn)識它的方法是每個事務(wù)都看到一個數(shù)據(jù)庫內(nèi)容的快照,而并發(fā)執(zhí)行的事務(wù)很可能看到不同的快照。 因此不管怎樣,整個"現(xiàn)在"的概念都是含混不清的。 不過如果客戶端應(yīng)用相互隔離,那么這就不是個大問題,但是如果客戶端之間在數(shù)據(jù)庫外部相互通訊,那就可能有嚴(yán)重的歧義。
要保證一行當(dāng)前實際存在和避免其被同時更新,我們必須使用SELECT FOR UPDATE, SELECT FOR SHARE,LOCK TABLE。 SELECT FOR UPDATE和SELECT FOR SHARE只是對其它的并發(fā)更新鎖住返回的行,而 LOCK TABLE 保護整個表。 當(dāng)從其它環(huán)境向PostgreSQL里用可串行化模式移植應(yīng)用時一定要把這些問題考慮進去。
在MVCC環(huán)境下,全局有效性檢查需要一些額外的考慮。 比如,一個銀行應(yīng)用可能會希望檢查一個表中的所有扣款總和等于另外一個表中的加款總和,同時兩個表還會被活躍地更新。 在讀已提交模式下比較兩個連續(xù)的SELECT sum(...)命令的結(jié)果是不可靠的, 因為第二個查詢很可能會包含第一個沒計算的事務(wù)提交的結(jié)果。 在一個可串行化的事務(wù)里進行兩個求和則給出在可串行化事務(wù)開始之前提交的所有事務(wù)產(chǎn)生精確的結(jié)果, 但我們還是會合理地置疑在結(jié)果提交的時候,它們是否還相關(guān)。 如果可串行化事務(wù)本身在試圖做一致性檢查之前進行了某些變更,那么檢查的有用性就更加值得討論了, 因為現(xiàn)在它包含了一些(但不是全部)事務(wù)開始后的變化。 在這種情況下,一個仔細(xì)的人會希望鎖住所有需要檢查的表,這樣才能獲得一個無可置疑的當(dāng)前現(xiàn)狀的圖像。 一個SHARE模式(或者更高級)的鎖保證在被鎖定表中除了當(dāng)前事務(wù)之外,沒有未提交的更新
還要注意如果我們依賴明確鎖定來避免并發(fā)更新,那么我們應(yīng)該使用讀已提交模式, 或者是在可串行化模式里在執(zhí)行命令之前小心地獲取鎖。 在可串行化事務(wù)里獲取的鎖保證了不會有其它正在運行的修改該表的事務(wù)存在,但是如果事務(wù)看到的快照提前獲取了鎖, 那么它可能提前把一些現(xiàn)在已經(jīng)提交的改變放到表中。 一個可串行化事務(wù)的快照實際上是在它的第一個查詢或者數(shù)據(jù)修改命令(SELECT,INSERT, UPDATE,DELETE)開始的時候凍結(jié)的, 因此我們可以在快照凍結(jié)之前明確獲取鎖。