0

次のコードがアプリケーション内の複数のスレッドから呼び出されている場合、デッドロックのリスクはありますか? このためにデータベースに接続するために使用されるトランザクションは、この呼び出しの直前に開かれ、戻ると閉じられます。アプリケーション: Java データベース: Oracle

  FUNCTION reserveWork(in_batch_id NUMBER,
                       in_work_size NUMBER,
                       in_contentType_id NUMBER) RETURN NUMBER IS
    rows_reserved NUMBER := 0;

  BEGIN
    UPDATE
          D_Q1
    SET
          DQ1_BAT_ID = in_batch_id
    WHERE
         DQ1_BAT_ID is null
         AND DCT_ID = in_contentType_id
         AND ROWNUM < (in_work_size + 1);

    rows_reserved := SQL%ROWCOUNT;

    RETURN (rows_reserved);

  END;
4

3 に答える 3

2

デッドロックが発生するには、次の 2 つの条件が必要です。

  1. 各トランザクションには複数のロックが必要です。

  2. ロックは別の順序で取得する必要があります。

各スレッドが複数の行をロックするため、条件 1 は true です。返される行の順序は決定論的ではないため、条件 2 は理論的には true です。たとえば、スレッド 1 は行 1、2、3 を更新しようとし、スレッド 2 は行 3、2、1 を更新しようとする場合があります。

実際には、Oracle は常に同じ順序で行を返す可能性があるため、デッドロックになることはありません。とにかく、ORA-00060 エラーを処理する準備をして、要求を再送信してください。

もう 1 つのアイデアは、これを 2 つのステップで行うことです。最初のプロシージャは SELECT * WHERE ... FOR UPDATE NO WAIT を実行して行をロックします。それが ORA-00054 を返さない場合、2 番目のプロシージャが実際の更新を実行します。それ以外の場合は、再試行します。

いずれにせよ、テーブルを同時に更新するのと同じ数のクライアントに設定された CREATE TABLE に INITTRANS があることを確認してください。

于 2009-02-04T22:24:58.727 に答える
1

同じテーブルで複数の UPDATE を実行している場合、明確なデッドロックのリスクがあります。

特に、コードに COMMIT または ROLLBACK が表示されないためですか? これはJDBCで行われていると思いますか?

UPDATE に時間がかかるほど、デッドロックのリスクが高くなります。

于 2009-02-04T17:54:46.900 に答える
1

デッドロックは、トランザクション A がレコードをロックし、トランザクション B がレコードをロック解除するのを待たなければならないときに、トランザクション B がトランザクション A によって既にロックされているレコードを待機しているときに発生します。

Oracle には、更新中にテーブルへの変更を処理するための非常に洗練されたメカニズムがあります。見る

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:11504247549852

一般に、デッドロックのリスクは、トランザクションの実行時間が長くなり、トランザクションが変更するデータが増えるほど増加します。これがデッドロックする可能性は低いと思いますが、「キューに入る」可能性があります。この SQL を実行している 3 つまたは 4 つの同時セッションがある場合、各セッションは SQL に対して同じ実行パスを持ち、更新のために同じ行を識別します。 1 人が先に到着し、他の人は待機します。その最初のトランザクションが完了すると、別のトランザクションがレコードを再取得し、それらが変更されていることを確認し、Tom Kyte の記事で説明されているように再起動して、次の一連の行を選択します。

11g を使用している場合は、使用できる SKIP LOCKED があります。以前のバージョンには存在しますが、文書化されていません。したがって、自己責任で使用してください。

http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_10002.htm#SQLRF01702

そのようにして、あなたは

SELECT primary_key BULK COLLECT INTO pk_variable_array FROM D_Q1
WHERE    DQ1_BAT_ID is null
AND DCT_ID = in_contentType_id
AND ROWNUM < (in_work_size + 1)
FOR UPDATE SKIP LOCKED;
--
FORALL i in 1..pk_variable_array
 UPDATE D_Q1
 SET DQ1_BAT_ID = in_batch_id
 WHERE primary_key = pk_variable_array(i)
于 2009-02-04T22:30:52.537 に答える