sql >> データベース >  >> RDS >> Oracle

OracleでアトミックMERGEを実行できますか?

    これは、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です。 2つのセッションで同時に呼び出すとどうなりますか?

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

    SSN1が最初にそこに到達し、一致するレコードが見つからないため、レコードを挿入します。 SSN2は2番目に到達しますが、SSN1がコミットする前に、レコードが見つからず、レコードを挿入してハングします SSN1は100の一意のインデックスノードをロックしているためです。SSN1がコミットすると、SSN2はDUP_VAL_ON_INDEX違反をスローします。

    MERGEステートメントはまったく同じように機能します。どちらのセッションもon (t23.id = 100)をチェックします 、それを見つけられず、INSERTブランチを下に移動します。最初のセッションは成功し、2番目のセッションはORA-00001を投げます。

    これを処理する1つの方法は、悲観的なロックを導入することです。 UPSERT_T23プロシージャの開始時に、テーブルをロックします。

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

    これで、SSN1が到着し、ロックを取得して、前と同じように進みます。 SSN2が到着すると、ロックを取得できないため、すぐに失敗します。これは2人目のユーザーにとっては苛立たしいことですが、少なくとも彼らはぶら下がっていません。さらに、他の誰かが同じレコードで作業していることを知っています。

    選択するものがないため、SELECT ...FORUPDATEと同等のINSERTの構文はありません。したがって、MERGEにもそのような構文はありません。あなたがする必要があるのは、MERGEを発行するプログラムユニットにLOCKTABLEステートメントを含めることです。これが可能かどうかは、使用しているフレームワークによって異なります。



    1. Oracleでnull値の列を合計する

    2. djangoでテーブルのchar列のエンコーディングを設定するにはどうすればよいですか?

    3. ユーザーが選択したcsvファイルをデータベースにインポートする方法

    4. 正規化または非正規化が機能するかどうかを判断できません