2016-09-16 7 views
0

各行のテーブルトランザクションでnumber_orderを生成する必要があります(順序は1,2,3 ...)。私の解決策は、テーブルトランザクションの挿入前にトリガーを作成することです。トリガーの使命は、テーブルの総行数をカウントすることです(トランザクションからカウント数を選択(1)からv_countまで選択) - >次にnew.num_order = v_count + 1を設定します。トリガーでマルチスレッドを処理する

このソリューションはほとんどの場合OKですが、多くのスレッドがテーブルに挿入され、マルチスレッドでトリガが実行され、SAME ORDERが返されます(理由はselectコマンドが同じ時刻で呼ばれ、挿入前には&と呼ばれます)。 これに代わる解決策を教えてください。前もって感謝します。 P/s:私はOracle 12cデータベースを使用しています。そして、順序は実際にはテーブルの他のいくつかの列(例えば:Room_id)に基づいているので、私はシーケンスを使用することはできません。したがって、完全なselectコマンドは次のとおりです。select count(1)to v_count from room_id =:new.room_id)

答えて

1

一般的に、これは重大なパフォーマンス、スケーリング、およびサポートの問題につながる悪いアプローチです。私はデザインを考え直すだろう。

これを行うには、トランザクションを強制的にシリアル化する必要があります。プライマリキーがroom_idroom_countの値を持つ別のテーブルを持つこともできますし、その列をroomに追加することもできます。 select for updateを使用してroom_idの行をロックする必要があります。その後、room_countを更新し、insertに使用します。トランザクションがコミットするとロックが解除されます。

ただし、これを行うと、同じroom_idを含むすべてのトランザクションがブロックされます。あなたが比較的短い取引をしている場合、同じ部屋で働くユーザーがあまりにも多くないと仮定すると、恐ろしいことではないかもしれません。しかし、ユーザー数やトランザクションの長さが増加するにつれて、問題はより困難になります。トランザクションに複数のルームが含まれる可能性がある場合は、デッドロックの可能性を回避するために、すべてのトランザクションを同じ順序(たとえば、room_idオーダー)で処理する必要があります。このテーブル以外にも同様のことをするつもりなら、事態はさらに複雑になります。

私は多くの場合、シーケンスを使用して、クエリで順次値を生成します。例

SELECT room_id, 
     rank() over (partition by room_id order by sequence_column) your_num_order 
    FROM your_table 

かについて、あなたは最初の挿入のためのsequence_columnを使用し、定期的に(毎日が一般的です)バックグラウンドジョブを持っており、取引が完了した後、バッチでnum_orderを割り当てることができます。

+0

ありがとうございます。しかし、このソリューションは私にとっては複雑なようです。 – Khoa

+0

@Khoa、あなたの要件の背後にある隠れたトラップが複雑なので、ソリューションは複雑です。 –

-1

私は解決策以下の提案ます: 新しいテーブル

create table room_count(room_id NUMBER primary key, cnt number); 

機能を自律型トランザクションでカウントをインクリメントする:

Create or replace function inc_room_cnt(p_room_id NUMBER) return number as 
PRAGMA autonomous_transaction; 
    v_cnt NUMBER; 
begin 
    update room_count set cnt = cnt +1 where room_id = p_room_id returning cnt into v_cnt; 

    -- insert new room if not yet exists 
    if SQL%ROWCOUNT = 0 then 
    v_cnt := 1; 
    insert into room_count values (p_room_id, v_cnt); 
    end if; 

    commit; 
    return v_cnt; 
end; 
/

before insertトリガーにあなたが設定しinc_room_cntを呼び出すことができます注文:

:new.room_order := int_room_cnt(:new.room_id); 
+0

ありがとうございます。 – Khoa