SELECT... for update,排他鎖機制的簡單理解
阿新 • • 發佈:2018-11-16
會話1中: 建立一個表 SQL> create table t0416a (id number,val number); Table created. 插入一行記錄並提交 SQL> insert into t0416a values (1,10); 1 row created. SQL> commit; Commit complete. 查看錶中的記錄,這時VAL列的值為10. SQL> select * from t0416a; ID VAL ---------- ---------- 1 10 假設操作人員認為應該對VAL列的值加5,使其等於15。則發出以下操作,但未提交。 SQL> update t0416a set val=val+5 where id=1; 1 row updated. 這時再開啟另一個會話,稱之為會話2.模擬另一位操作人員。 檢視該表中的值,顯示VAL的值仍為10。這是正確的。因為會話1中的修改未提交。 SQL> select * from t0416a; ID VAL ---------- ---------- 1 10 操作人員2也發現這個值不對,應該對VAL列的值加5,使其等於15.操作人員2在會話2中也發起對這個值的修改。 SQL> update t0416a set val=val+5 where id=1; 但由於會話1中對該行記錄的修改未提交,所以,排它鎖並沒有釋放,因而操作人員2發起的這個修改操作會等待,直至會話1釋放該鎖(提交或回滾)。 假設這時操作人員1在會話1中提交了。(注意,此時會話2中的修改獲得了鎖,修改也生效了,但未提交。) SQL> commit; Commit complete. 操作人員1這時做檢查,發現VAL值如其期望的一樣,是15. SQL> select * from t0416a; ID VAL ---------- ---------- 1 15 再回到會話2.這時操作人員2發現自己的語句已經執行了,但如果他這時檢查一下,會發現VAL列的值並不是其期望的15,而20了。 SQL> select * from t0416a; ID VAL ---------- ---------- 1 20 但很多時候,我們是不會去做這個確認,通常一看語句成功執行,會一如往常提交之。 SQL> commit; Commit complete. 但一旦這樣做了,資料已經被改成了並不是我們所期望的值。這時,無論是在哪個會話中,檢視這個VAL值,均會是20. 而造成這個問題的原因,是因為oracle的一個重要特性:一致性讀。正是這個特性,使得ORACLE讀不阻塞寫,寫也不會阻塞讀,這個特點使得ORACLE的併發效能很好。 但如上面的實驗所示,這樣一來,當多人在同時修改(在其它人提交修改前,也發出了修改命令),而且還是對同一條記錄的同一個列做修改時,就會發生錯誤。 這時,我們就可以用for update來避免這個問題。 即,在我們試圖修改某個記錄時,先利用select ... from xxx where zzz for update;將該記錄加鎖。這樣,就可以確保我現在看到的值,一定不會再被其他人修改了。 用上面演示的例子來說,這時我看到的VAL值是10,那麼就一定是10。如果這時其上有其它人未提交的修改,那麼我前面發出的select ... from xxx where zzz for update; 語句是處於等待狀態,不會返回結果。只要它能返回結果,就一定是已經在這條記錄上加鎖了,從此刻起,其它人是不可能對其進行修改的。那麼我對其修改後,其結果 一定是期望的15,而不會出現上例中出現的20. |