Oracle
 sql >> база данни >  >> RDS >> Oracle

Мога ли да направя атомно MERGE в Oracle?

Това не е проблем с 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;

И така, това е PL/SQL еквивалентът на MERGE на T23. Какво се случва, ако две сесии го извикат едновременно?

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. Дали това е възможно за вас зависи от рамката, която използвате.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wildfly не успя да зареди модул за Oracle драйвер

  2. Проблем със създаването на чужд ключ в Oracle

  3. PL/SQL:ORA-00904:невалиден идентификатор &PL/SQL:Изявлението е игнорирано&PLS-00364:използването на променливата на индекса на цикъл е невалидно

  4. ORA-29902:грешка при изпълнение на подпрограма ODCIndexStart() ORA-20000:Грешка в текста на Oracle:DRG-50901:грешка в синтаксиса на анализатора на текстова заявка на ред 1, колона 19

  5. Дали индексът е клъстерен или неклъстериран в Oracle?