わかりやすい JPA(11)
データベースの特質とロック

はじめに

データベースのロックとはどういう機能でしょうか。また、どうしてそのような機能が必要なのでしょう。今回は、データベースの特質から明らかとなる、ロック機能の意義と概要について解説します。

データベースの特質

データベースでは、トランザクションという用語がしばしば出てきますが、これは、「現金出納簿から○円を差引き、同額の消耗品を消耗品台帳に計上する」というような、ひとまとまりのデータベース操作を意味しています。

トランザクションが、安全・確実に実行されるためには、ひとまとまとりの処理なら処理全体が最後まで正しく完了しないかぎり、処理全体を失敗させなくてはいけません(原子性という)。また、複数のトランザクションが平行して実行される時、1つのトランザクションは、他のトランザクションから影響を受けないようにすることも必要です(独立性という)。

そのため、データベースでは、テーブルの特定の行データに対する同時書き込みはできないようになっています。しかし、トランザクションの独立性を確保するにはそれだけでは十分ではありません。異常な状態は、ある確率で、テーブル更新の手順やテーブル間の関係などから発生する可能性があります。

トランザクションの独立性が確保されないとどうなるか

トランザクションの独立性を確保するには、極端な場合、1つのトランザクションが終了した後に、初めて次のトランザクションを開始するようにすればよいのですが、これだと効率が悪く、処理性能がでません。独立性と処理性能のバランスをどう取るかが大切です。

ところで、プログラマが対処しないと起こるであろう典型的な異常事態のパターンが3つあります。いずれも2つ以上のトランザクションが平行して実行される時に起こる異常事態です。

異常事態 説 明
ダーティリード
Dirty Read
他のトランザクションが更新途中のデータを読みだしてしまう
非再現性リード
Non Repeatable Read
トランザクションの途中で、他のトランザクションがデータを更新するため、同じデータでも、読み込むたびに値が変わってしまう
ファントム(幽霊)リード
Phantom Read
トランザクションの途中で、他のトランザクションがデータを挿入あるいは削除したことにより、関係のあるデータの処理結果が正しくなくなる

ただ、どのようなデータベースシステムでも、トランザクションの中で、このような異常を検知するための機能が組み込まれています。それを一般に「ロック」といいます。JPAでも、これらの異常事態を自動検知するために、独自のロック機能を利用できます。ただし、ロック機能は想定される異常事態の種類に応じて、正しく適用する必要があります。

ロックの概要

発生する異常事態は、「ロックをかける」ことによって防ぐことができます。JPAに用意されているロックは楽観的ロック(Optimistic Loc)と悲観的ロック(Pesimisstic Loc)の2種類です。これも表にしておきましょう。

種 類 説 明
楽観的ロック トランザクションのコミット時に、エンティティのバージョンフィールドを比較することでロックの役割を果たす
悲観的ロック トランザクションの開始時からロックをかけ、コミットするまで開放しない。DBMSの機能を利用したロック方法。

楽観的ロックでは、コミット時に、他のトランザクションと衝突することはまずないだろう、と楽観的に考えます。「まあ、ないだろうけれど、コミット時にチェックしてみて、他のトランザクションと衝突していたら、その時はあきらめてロールバックすればいい」と考える場合のロックです。そのためにバージョンフィールド(次回解説)を利用します。

一方、悲観的ロックはこれと逆で、どうせ他のトランザクションと衝突するに決まっているから、それなら最初からロックをかけておこう、というものです。RDBMSの機能を利用しています。これなら、かなり確実ですが、その分、性能は犠牲になります。

楽観的ロックと悲観的ロックのどちらを使うべきかは、プログラマの判断です。アクセス頻度、重要度、サーバーの数や性能などを考えて決定します。ただ、ロックに検知されてトランザクションが失敗するのは許容できますが、ロックにかからないで異常事態が起こることは避けねばなりません。それには、どんな異常事態が起こり得るかよく考える必要があります。

一般的な方針としては、まず全体に楽観的ロックを適用しておき、それでも問題が置きそうな箇所があれば、楽観的ロックのかけ方を工夫します。そして、なお問題がおきそうなクリティカルなケースがあれば、やむなく悲観的ロックを適用することにします。

読者になる

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

%d人のブロガーが「いいね」をつけました。