2009-02-19 57 views
0

我找到下面的代碼:以錯誤的方式插入Oracle - 如何處理它?

select max(id) from TABLE_NAME ... 

... do some stuff ... 

insert into TABLE_NAME (id, ...) 
VALUES (max(id) + 1, ...) 

我可以創建適用於PK的序列,但有一串現有的代碼(傳統的ASP中,現有的asp.net應用不屬於這一部分項目),它不會使用它。

我應該忽略它,還是有辦法解決它而不進入現有的代碼?

我想,最好的選擇就是要做到:

insert into TABLE_NAME (id, ...) 
VALUES (select max(id) + 1, ...) 

選項?

回答

2

您可以在表上創建一個觸發器,使用您從序列中獲取的值覆蓋ID的值。 這樣你仍然可以使用其他現有的代碼,並且沒有併發插入的問題。

如果你不能改變其他軟件,他們仍然做選擇最不幸的最大(id)+1插入。然後你可以做的是:

對於你自己的插入使用一個序列並用-1 *(序列值)填充ID字段。 這種插入方式不會干擾現有程序,也不會與現有程序衝突。 (做沒有id值的插入,並使用觸發器以序列的負值填充ID)。

0

大問題:有人靠PK的價值嗎?如果沒有,我會建議使用觸發器,從序列中獲取id並設置它。插入不會指定和id。

我不知道,但

INSERT INTO TABLE_NAME(ID,...) VALUES(SELECT MAX(ID)+ 1,...)

可能會導致問題何時會話達到該代碼。可能是oracle讀取表(計算max(id)),然後嘗試獲取插入PK的鎖。如果是這種情況,兩個併發會話可能會嘗試使用相同的ID,從而在第二個會話中導致異常。

您可以添加一些日誌記錄到觸發器,以檢查插入是否得到處理已經有一個ID集。所以你知道你還需要尋找一些使用舊代碼的地方。

1

正如其他人所說,您可以使用序列覆蓋數據庫觸發器中的最大值。

select max(id) from TABLE_NAME ... 

... do some stuff ... 

insert into TABLE_NAME (id, ...) 
VALUES (max(id) + 1, ...) 

insert into CHILD_TABLE (parent_id, ...) 
VALUES (max(id) + 1, ...) 
+0

不幸的是,那是什麼似乎發生 - 第一選擇MAX(id)返回「新」的ID,並將周圍,所以使用觸發器爲忽略插件將無法正常工作。 – chris 2009-02-19 16:01:26

1

插入行觸發之前使用seqeunce在:但是,如果任何應用程序代碼中使用該值這樣可能導致問題。選擇max(id)+ 1在多個相關環境中不起作用。

+0

在選擇之前,您可以嘗試LOCK TABLE table_name IN EXCLUSIVE MODE。它會少併發但不會中斷。 – 2009-02-19 22:02:09

1

這很快轉向討論應用程序架構,特別是當問題歸結爲「我該怎麼做?「

Oracle中的主鍵真的需要來自序列,因爲您在應用程序代碼中處理複雜的插入邏輯(至少是父/子插入),您應該像現在說的那樣進入現有代碼(因爲觸發器可能不會幫助你)

在一個極端,你可以從應用程序直接取消SQL訪問,並讓它們調用服務,以便插入/更新/刪除代碼可以集中化,或者你可以重寫你的代碼使用某種MVC架構的。我假設都是矯枉過正您的具體情況。

是ID列至少設置爲一個真正的主鍵,所以有將保持duplicat約束es發生了嗎?如果沒有,從那裏開始。

一旦主鍵到位,或者如果它已經是,它直到插入啓動失敗只是時間問題;你會知道他們什麼時候開始失敗,對吧?如果沒有,請進入錯誤日誌記錄。

現在修復應用程序代碼。當你在那裏時,你至少應該編寫並調用幫助程序代碼,以便數據庫交互儘可能少。然後爲其他開發人員提供一些領導,並確保他們也使用助手代碼。

0

它可以通過一個變量取最大值,然後只需將其插入到表像

聲明 v_max INT進行; 從表中選擇max(id)到v_max;

插入到表中的值((v_max + ROWNUM),VAL1,VAL2 ....,VALN); 承諾;

這將創建在一個單一的序列以及批量插入。

+0

這完全錯了。選擇max(id)是當前代碼正在做的事情,這不是正確的做事方式。 – chris 2013-02-18 16:59:51