まず、テーブルをロックしても、別のセッションがSELECT
を発行するのを防ぐことはできません。 データに対するステートメント。
セッション1で、テーブルをロックすると
SQL> lock table foo in exclusive mode;
Table(s) Locked.
その後、セッション2を開始して、必要なすべてのデータをクエリできます
SQL> select * from foo;
COL1
----------
1
1
Oracleでは、ライターはリーダーをブロックしないため、別のセッションがテーブル内のデータをクエリするのを防ぐことはできません。
実装しようとしているのは悲観的なロックのようです。その場合、テーブルをロックするのではなく、SELECT FOR UPDATE
を実行します。 処理しようとしている特定のエントリをロックします。他のすべてのセッションもSELECT FOR UPDATE
を実行しようとする限り (Oracleのバージョンによっては、SKIP LOCKED
が追加される可能性があります 修飾子および/またはWAIT
修飾子)。これにより、処理している特定の行がロックされ、実装の詳細に応じて、2番目のセッションで別の行を選択するかタイムアウトするか、処理する行がないことがわかります。テーブルをロックする必要はありません。
ロックを解放する唯一の方法は、ロックを取得したセッションがロックを解放する(通常はトランザクションを終了する)か、ロックを取得したセッションを終了することです。クライアントアプリケーションがまだ実行されているが、ロックを解放したりセッションを終了したりするために何もしていない場合、ロックは無期限に保持されます。 DBAは、セッションを明示的に強制終了し、トランザクションをロールバックさせてロックを解放し、システムを再び動かす必要があります。クライアントアプリケーションの実行が停止するか、少なくとも応答が停止する場合(説明している障害シナリオが正確にわからない場合)、'SQLNET.EXPIRE_TIME'パラメーター データベースレベルでは、データベースはクライアントが応答していないと判断し、セッションを自動的に強制終了し、トランザクションをロールバックしてロックを解除します。
ただし、データを処理するセッションが複数ある場合は、通常、何らかの形式の楽観的ロックを使用することをお勧めします。それ以外の場合は、ビジネスユーザーを再び機能させるために、DBAがセッションを緊急に見つけて強制終了する必要があり、忙しくなるほど多くの介入が必要になるシステムを設計しています。これは、DBAが喜んで行うことではなく、ビジネスユーザーが不満を言うことを楽しむことでもありません。単純な楽観的ロックスキームは次のようになります
- 処理するキーと、行が最後に更新された時刻を示すある種の日付を選択します。
- ステータス列を「処理中」に更新して、他のセッションが同じ行を処理しようとしないようにします。
- アプリケーションのエントリを処理します
- 処理が完了したら、最初のステップで選択したキーと時刻を使用してデータを更新します。 1行を更新すると、選択してから他のセッションが問題のデータを変更していないことがわかります。 0行を更新すると、選択してから他のセッションがデータを変更したことがわかります。
この種のアーキテクチャを使用すると、データベースにクエリを実行して、処理されている行を確認したり、たとえば、クライアントが処理していない場合に、一定期間後にステータス列を「未処理」に戻すジョブを実行したりするのは比較的簡単です。終了した。他のセッションが処理する別の行を選択するのは非常に簡単です。また、たとえば、アプリケーションが数時間フリーズしてから回復した場合、処理が完了すると、他のセッションがすでに行を再処理していることがわかるため、比較的安全です。