采用防御式編程技術(shù)來構(gòu)建真正可移植的數(shù)據(jù)庫應(yīng)用。
場景:為每一行生成一個唯一的主鍵,
scott@ORCL>create?table?id_table
??2??(id_name?varchar2(30)?primary?key,
??3??id_value?number);
表已創(chuàng)建。
scott@ORCL>insert?into?id_table?values('MY_KEY',0);
已創(chuàng)建?1?行。
scott@ORCL>commit;
提交完成。?為了得到一個新的鍵,必須執(zhí)行以下代碼:
scott@ORCL>update?id_table ??2??set?id_value=id_value+1 ??3??where?id_name='MY_KEY'; 已更新?1?行。 scott@ORCL>select?id_value ??2??from?id_table ??3??where?id_name='MY_KEY'; ??ID_VALUE ---------- ?????????1
問題有:
1.一次只能有一個用戶處理事務(wù)行,需要更新這一行來遞增計數(shù)器,這會導(dǎo)致程序必須串行完成這個操作。
2.在oracle中,倘若隔離級別為serializable,除第一個用戶外,視圖并發(fā)完成此操作的其他用戶都會接到這樣一個錯誤:ORA-08117:can't serialize access for this transaction (無法串行訪問這個事務(wù))
scott@ORCL>set?transaction?isolation?level?serializable; set?transaction?isolation?level?serializable * 第?1?行出現(xiàn)錯誤: ORA-01453:?SET?TRANSACTION?必須是事務(wù)處理的第一個語句 scott@ORCL>commit; 提交完成。 scott@ORCL>set?transaction?isolation?level?serializable; 事務(wù)處理集。
scott@ORCL>update?id_table ??2??set?id_value=id_value+1 ??3??where?id_name='MY_KEY'; 已更新?1?行。 scott@ORCL>select?id_value ??2??from?id_table ??3??where?id_name='MY_KEY'; ??ID_VALUE ---------- ?????????2
下面,再到另一個sql*plus會話中完成同樣的操作,并發(fā)的請求唯一的ID:
scott@ORCL>set?transaction?isolation?level?serializable; 事務(wù)處理集。 scott@ORCL>update?id_table ??2??set?id_value=id_value+1 ??3??where?id_name='MY_KEY';
此時它會阻塞,因?yàn)橐淮沃挥幸粋€事務(wù)可以更新這一行。這展示了第一個問題,即這個會話會阻塞,并等待該行提交。
由于我們使用的是oracle,而且隔離級別是serializable,提交第一個會話的事務(wù)時會觀察到以下行為:
scott@ORCL>commit; 提交完成。
第二個會話會立即顯示以下錯誤:
scott@ORCL>update?id_table ??2??set?id_value=id_value+1 ??3??where?id_name='MY_KEY'; update?id_table * 第?1?行出現(xiàn)錯誤: ORA-08177:?無法連續(xù)訪問此事務(wù)處理
對于這個問題,正確解法:
scott@ORCL>create?table?t
??2??(pk?number?primary?key,
??3??name?varchar2(50));
表已創(chuàng)建。
scott@ORCL>create?sequence?t_seq;
序列已創(chuàng)建。
scott@ORCL>create?trigger?t_trigger?before?insert?on?t?for?each?row
??2??begin
??3??select?t_seq.nextval?into?:new.pk?from?dual;
??4??end;
??5??/
觸發(fā)器已創(chuàng)建
scott@ORCL>insert?into?t(name)?values('yin');
已創(chuàng)建?1?行。
scott@ORCL>insert?into?t(name)?values('xian');
已創(chuàng)建?1?行。
scott@ORCL>select?*?from?t;
????????PK?NAME
----------?--------------------------------------------------
?????????1?yin
?????????2?xian其效果是為所插入的每一行自動地(而且透明地)指定一個唯一鍵。
還有一個更優(yōu)的方法,完全沒有觸發(fā)器的開銷(首選方法):
scott@ORCL>insert?into?t?values(t_seq.nextval,'wangwang'); 已創(chuàng)建?1?行。 scott@ORCL>insert?into?t?values(t_seq.nextval,'qqq'); 已創(chuàng)建?1?行。 scott@ORCL>select?*?from?t; ????????PK?NAME ----------?-------------------------------------------------- ?????????1?yin ?????????2?xian ?????????4?wangwang ?????????6?qqq





