下記の記事で、ご紹介させて頂きましたが、DBMSは、「トランザクションを競合させないよう」にするため、自動的に「ロック」を行います。
ただ、開発者が明示的にロックをかけることも可能です。
明示的にかけることができるロックの種類
種類 | 説明 |
---|---|
行ロック | 特定の1行にロックをかける。 |
表ロック | 特定のテーブルにロックをかける。 |
データベースロック | データベース全体にロックをかける。 |
ロックエスカレーション
一つのテーブルに対して、膨大な行のロックをするのは大変です。
DBMSによっては、ロックする行の数に応じて、表ロックに切り替わる「ロックエスカレーション」という機能があります。
明示的にかけることができるロックの厳しさ
また、「ロックの種類」だけでなく、「ロックの厳しさ」も設定することが可能です。
下記の2種類に分かれます。
- 排他ロック
- 共有ロック
共有ロック
他からの共有ロックを許可するため、データの読み取りに利用される。
他のトランザクションから参照(SELECT)のみは可能です。
通常のSELECT文で選択した行には、自動的にこの「共有ロック」がかかる。
排他ロック(占有ロック)
他からのロックを一切許可しないため、更新処理に利用される。
SELECT文の末尾に「FOR UPDATE」を指定すると、この「排他ロック」がかかり、他のトランザクションから書き換えることができなくなる。
排他ロックで、処理を待たせたくない場合
排他ロックは、通常ロックが解除されるまで待つことになります。処理によっては、かなり時間がかかってしまいますね。
アプリによっては、待ち時間を作りたくないシステムもあると思います。
それをしたくない場合は、「FOR UPDATE(NOWAIT)」と指定することで、ロック失敗のエラーを返し、トランザクションを即終了させることができます。
「デッドロック」について
下記の図のように、トランザクション同士のロックが、交差してしまう場合です。
引用:https://terasolunaorg.github.io/guideline/5.0.1.RELEASE/ja/ArchitectureInDetail/ExclusionControl.html
デッドロックの対策
そもそも、DBMSでデッドロックを解消する仕組みがある。
多くのDBMSでは、自動でデッドロックを解消する仕組みがあります。
定期的にデッドロックが発生している箇所がないか探して、片方のトランザクションを強制終了させることで、デッドロックから解放します。
ただ、トランザクションが失敗してしまっているので、できるだけ避けたいところです。
開発者側での対策
トランザクションの時間を短くする。
ロックしている時間が短いほど、他のトランザクションと競合する可能性が減ります。
同じ順番でロックをかけるようにする。
そもそも、デッドロックは、「相手とロックの順番が交差すること」が原因なので、交差しないようにできるだけ同じ順番でロックをかけるようにSQLを工夫します。
この記事へのコメントはありません。