sql >> Databáze >  >> RDS >> Oracle

Mohu provést atomové MERGE v Oracle?

S MERGE jako takovým to není problém. Problém spočívá spíše ve vaší aplikaci. Zvažte tuto uloženou proceduru:

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;

Toto je PL/SQL ekvivalent MERGE na T23. Co se stane, když to zavolají dvě relace současně?

SSN1>  exec upsert_t23(100, 'FOX IN SOCKS')

SSN2>  exec upsert_t23(100, 'MR KNOX')

SSN1 se tam dostane jako první, nenajde žádný odpovídající záznam a vloží záznam. SSN2 se tam dostane jako druhý, ale před potvrzením SSN1 nenajde žádný záznam, vloží záznam a zablokuje se protože SSN1 má zámek na jedinečném indexovém uzlu na 100. Když SSN1 potvrdí SSN2, vrhne narušení DUP_VAL_ON_INDEX.

Příkaz MERGE funguje úplně stejně. Obě relace zkontrolují on (t23.id = 100) , nenajděte ji a přejděte dolů po větvi INSERT. První relace bude úspěšná a druhá vrhne ORA-00001.

Jedním ze způsobů, jak to zvládnout, je zavést pesimistické zamykání. Na začátku procedury UPSERT_T23 uzamkneme tabulku:

...
lock table t23 in row shared mode nowait;
open c;
...

Nyní dorazí SSN1, uchopí zámek a pokračuje jako předtím. Když SSN2 dorazí, nemůže získat zámek, takže okamžitě selže. Což je pro druhého uživatele frustrující, ale alespoň nevisí a navíc vědí, že na stejném záznamu pracuje někdo jiný.

Neexistuje žádná syntaxe pro INSERT, která je ekvivalentní SELECT ... FOR UPDATE, protože není co vybírat. A tak žádná taková syntaxe neexistuje ani pro MERGE. Co musíte udělat, je zahrnout příkaz LOCK TABLE do programové jednotky, která vydá MERGE. Zda je to pro vás možné, závisí na frameworku, který používáte.



  1. Virtuální sloupce a funkční indexy

  2. mysql připojit ON a AND k laravel výmluvný

  3. Jak mohu použít operátor Postgresql ANY v příkazu NOT IN

  4. mysql_connect returning Nemůžete se připojit k místnímu serveru MySQL přes soket na připojení vzdáleného hostitele?