由Oracle觸發器死鎖及行級鎖限制所衍生的解決方案

regonly1發表於2009-06-28

這裡主要對前面觸發器死鎖那篇文章的具體化說明:
首先建立臨時表(session級)。
create global temporary table tilog(
rid urowid,
lock_flag,
update_flag,
tmstmp timestamp(6)) on commit preserve rows;
由於是session級的,且觸發器在內部不斷巢狀觸發過程中都是處於同一個session期。所以該臨時表適合於此種情況,而且適合於多併發的環境。
解決思路:
觸發器為update T表的時候觸發。觸發級別為for each row;
假設客戶編號C下面有A1、A2、A3三個帳號。

       步驟1:當對T表執行update語句的時候,即已經鎖定了對應update所對應的行A1。此時,把對應的更新的這些行的rowid,鎖定標識(lock_flag=1),更新標識(update_flag=0),時間戳(cast(sysdate as timestamp))存放到臨時表tilog。
然後根據客戶編號,找到對應的其他賬戶編號(A2、A3)。並批次放入到陣列中(bulk collect into)。

        步驟2:從陣列中迴圈取出一個賬戶編號A2,並從tilog中查詢該記錄的鎖定情況和更新情況。這裡對於A2,tilog中尚未存在該記錄。因此判斷為無鎖定和無更新。直接進入更新語句update。

        步驟3:此時就又觸發了該觸發器,往tilog中插入A2的資訊(rowid,lock_flag=1,update_flag=0,timestamp)。然後再次由客戶編號得到A2外的兩個賬戶編號A1和A3。然後從tilog中查詢A1對應的鎖定和更新的資訊。由步驟1可得到對應A1目前處於鎖定狀態。因此不能執行update(否則造成死鎖)。因而迴圈到A3。A3的更新跟步驟相同。往tilog中插入對應鎖定和更新的資訊。

        步驟4:A3觸發後進入觸發器的第三次觸發。此時根據A3從tilog中找到的A1和A2都是鎖定的記錄了。於是第三次觸發完成,跳出,執行commit,解除行鎖定標識並更新A3記錄的更新標識為1(標識該記錄已更新)。

        步驟5:A3完成後,步驟3中對A2也進行commit及更新標識置1。然後回到步驟1。再次進入A3,從tilog中取出更新標識和鎖定標識。由於此時更新標識為1,即已更新。不再對該記錄進行處理。

        步驟6:再次回到步驟1,更新A1記錄。此次觸發全過程完成。更新行鎖定標識為0及行更新標識為1。

下面是一個簡單的更新流程跟蹤:
c_fundacco=680760000029 islocked=0 isupdated=0
update->680760000029
c_fundacco=681850000091 islocked=1 isupdated=0
681850000091 is LOCKED!
c_fundacco=681850000079 islocked=0 isupdated=0
update->681850000079
c_fundacco=681850000091 islocked=1 isupdated=0
681850000091 is LOCKED!
c_fundacco=680760000029 islocked=1 isupdated=0
680760000029 is LOCKED!
c_fundacco=681000000027 islocked=0 isupdated=0
update->681000000027
c_fundacco=681850000091 islocked=1 isupdated=0
681850000091 is LOCKED!
c_fundacco=680760000029 islocked=1 isupdated=0
680760000029 is LOCKED!
c_fundacco=681850000079 islocked=1 isupdated=0
681850000079 is LOCKED!
commit[u]-unlock-updated->681000000027
commit[u]-unlock-updated->681850000079
c_fundacco=681000000027 islocked=0 isupdated=1
681000000027 is UPDATED!
commit[u]-unlock-updated->680760000029
c_fundacco=681850000079 islocked=0 isupdated=1
681850000079 is UPDATED!
c_fundacco=681000000027 islocked=0 isupdated=1
681000000027 is UPDATED!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12932950/viewspace-607753/,如需轉載,請註明出處,否則將追究法律責任。

相關文章