यह MERGE के साथ ऐसी कोई समस्या नहीं है। बल्कि समस्या आपके आवेदन में है। इस संग्रहीत कार्यविधि पर विचार करें:
create or replace procedure upsert_t23
( p_id in t23.id%type
, p_name in t23.name%type )
is
cursor c is
select null
from t23
where id = p_id;
dummy varchar2(1);
begin
open c;
fetch c into dummy;
if c%notfound then
insert into t23
values (p_id, p_name);
else
update t23
set name = p_name
where id = p_id;
end if;
end;
तो, यह T23 पर MERGE के PL/SQL समतुल्य है। क्या होता है यदि दो सत्र इसे एक साथ बुलाते हैं?
SSN1> exec upsert_t23(100, 'FOX IN SOCKS')
SSN2> exec upsert_t23(100, 'MR KNOX')
SSN1 पहले वहां पहुंचता है, कोई मिलान रिकॉर्ड नहीं पाता है और एक रिकॉर्ड सम्मिलित करता है। SSN2 वहां दूसरे स्थान पर जाता है लेकिन SSN1 के आने से पहले, कोई रिकॉर्ड नहीं पाता, एक रिकॉर्ड सम्मिलित करता है और हैंग हो जाता है क्योंकि SSN1 में 100 के लिए अद्वितीय इंडेक्स नोड पर लॉक है। जब SSN1 SSN2 करता है तो DUP_VAL_ON_INDEX उल्लंघन होगा।
MERGE स्टेटमेंट ठीक उसी तरह काम करता है। दोनों सत्र on (t23.id = 100)
की जांच करेंगे , इसे न ढूंढें और INSERT शाखा में जाएं। पहला सत्र सफल होगा और दूसरा ORA-00001 को पछाड़ देगा।
इसे संभालने का एक तरीका निराशावादी लॉकिंग शुरू करना है। UPSERT_T23 प्रक्रिया की शुरुआत में हम तालिका को लॉक करते हैं:
...
lock table t23 in row shared mode nowait;
open c;
...
अब, SSN1 आता है, ताला पकड़ता है और पहले की तरह आगे बढ़ता है। जब SSN2 आता है तो उसे लॉक नहीं मिल सकता है, इसलिए यह तुरंत विफल हो जाता है। जो दूसरे उपयोगकर्ता के लिए निराशाजनक है लेकिन कम से कम वे लटक नहीं रहे हैं, साथ ही उन्हें पता है कि कोई और उसी रिकॉर्ड पर काम कर रहा है।
INSERT के लिए कोई सिंटैक्स नहीं है जो SELECT ... FOR UPDATE के बराबर है, क्योंकि चयन करने के लिए कुछ भी नहीं है। और इसलिए MERGE के लिए भी ऐसा कोई सिंटैक्स नहीं है। आपको जो करना है वह प्रोग्राम यूनिट में LOCK TABLE स्टेटमेंट को शामिल करना है जो MERGE जारी करता है। आपके लिए यह संभव है या नहीं यह आपके द्वारा उपयोग किए जा रहे ढांचे पर निर्भर करता है।