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