アプリケーション開発におけるロックの重要性とORMにおけるロックの実現例〜楽観的ロックの紹介〜2018.08.24アプリケーション開発におけるロックの重要性とORMにおけるロックの実現例〜楽観的ロックの紹介〜Tweet前回、「アプリケーション開発におけるロックの重要性とORMにおけるロックの実現例」ではロックについて掘り下げ、トランザクションについてとその特徴を紹介し、その中で楽観的ロックの存在を挙げました。そこで、今回は楽観的ロック及び悲観的ロックについて紹介したいと思います。データの不整合が発生する状態とトランザクションの分離レベルについて詳細を紹介し、続いて楽観的ロックと悲観的ロックについて紹介していきます。トランザクションの分離レベルデータの不整合ロックによりデータの不整合が発生することを防ぐことができますが、不整合が発生するケースは様々です。データの不整合を全て防ごうとすると可用性や性能が著しく低下するため、どの程度まで不整合を許容するかを考え、それに見合ったトランザクションの分離レベルを選択する必要があります。levels」から取り上げると次の項目が挙げられます。二度と呼び出せなくなってしまった状態である。書き込むことで発生する不整合である「※」が付いた不整合状態は、コミット前の値は参照できない前提で考えると問題の本質が分かりやすいと思われます。(それでも防げない状態であるため)リードスキューとライトスキューを除く各状態について、以下に例を用いて問題が発生するまでのシーケンスを図示します。ダーティライトダーティライトとは「複数のトランザクションが同じエンティティを更新した後、あるトランザクションがロールバックした場合に戻すべき値が不明となった状態」です。戻すべきか判断できない状態となります。Update)ロストアップデートとは「とあるトランザクションが書き込んだ値が、他のトランザクションにより上書きされた状態」です。更新が失われてしまいます。ロールバックされずにトランザクションに利用されることになってしまった状態」です。保持し続けてしまいます。二度と呼び出せなくなってしまった状態」です。ダーティリードを防ぐために、他のトランザクションがコミットする前のエンティティは参照できないようにしても発生します。ファントムリードファントムリードとは「とあるトランザクションがテーブルを読み込んだ後に、他のトランザクションによりエンティティが挿入された場合、再度テーブルを読み込むと挿入されたエンティティが参照できてしまう状態」です。ファジーリードを防ぐために、トランザクション処理中に読み取ったエンティティの値は常に同じとなるようにしても発生します。追加されたテーブルが読み込まれるようになります。実行することで全てのケースを防ぐことが出来ます。よって定義されています。READとあるトランザクション処理の間、同じエンティティであればいつ読み取っても同じ値となるよう分離するSERIALIZABLE複数のトランザクション処理結果が、シリアルに実行された場合と同じ結果になるよう分離するそれぞれの分離レベルにおいてデータ不整合発生可否をまとめると次のようになります。標準における分離レベルを再定義・拡張させた分離レベルが定義されています。トランザクション分離レベルを明確に定義し、それらの分離レベルでは防ぐことのできないデータ不整合が発生する状態を追加し、それらに含むトランザクション分離レベル毎の発生可否を整理しています。近い分離レベルを保つことができ、並列で実行することのできるレベルであると述べています。よって分離レベル名が異なっていたりするようです。Isolationとある時点において取得したスナップショットに対してトランザクション操作を行うことで、ファントムリードを防げるよう分離する分離レベルの再定義は割愛して、トランザクションの分離レベルとデータの不整合発生可否をまとめると次のようになります。<反例>×...発生する、〇...発生しない、△...一部発生する分離レベルの選択トランザクションの分離レベルの種類と、それに応じて防ぐことのできるデータ整合性について紹介しましたが、結論としてはどのような目的・環境においても最適となる分離レベルは存在せず、可用性と性能のトレードオフで選択することになります。おけるデフォルトの分離レベルを紹介します。ロックの有効期間と楽観的アプローチトランザクションの分離レベル以外の観点として、ロックの有効期間の違いによってもデータの不整合状態を防げる可能性の違いと性能の違いが生まれます。トランザクションが開始されてから終了するまでの間ずっとロックを行うことで不整合を防げる可能性は高まりますが、ロックが解放されるまでの待ち時間が増えることになります。一方で、読込・更新操作の間だけロックをかけることで待ち時間は少なくなりますが、今度は不整合が発生する可能性が高まります。そこで、不整合が発生するような更新が同時に行われる頻度によるアプローチの違いを紹介します。Locking)概要悲観的ロックは更新が同時に行われる頻度が高いことを想定しており、読込・更新処理が開始された時点で他の処理を排除するロック方式です。レベルで行なわれます。書き込み操作が主に行われる用途に対して適したロック方式です。等との相性が悪い(ロックかけっぱなしが発生しうる)とされています。更新が同時に行われる頻度は低いだろうという楽観的な考えに基づくロック方式です。ロックと言いつつも、データに対してのロックは行わずに競合の検証のみを行います。悲観的ロックの対となる方式です。マッパーによりアプリケーションレベルで実装されています。あることが一般的のようです。マッパーの実装に依存するとは思いますが、そもそも同時更新が行われる頻度が低い前提なので、カラム単位で設定するメリットが少ないのだと思います)ロックの仕組みは次のとおり単純なものです。競合が発生したと判断して、トランザクション処理を失敗させるここで、上記説明の中で事前の定義なく「バージョン(を示すカラム)」と記載しましたが、楽観ロックを使うためにはテーブルのレコードにバージョンを示すカラムを用意する必要があります。カラムを追加するマイグレーションファイルを作成してマイグレーションを実行することになります。ロック動作のシーケンス下記にロック未使用時と楽観的ロック使用時のシーケンス図を示します。このように、楽観的ロックはエンティティに対するロックは行わず、更新処理の開始時点とコミット時点のバージョンを比較することで更新処理が競合したことを検証します。防ぐことのできるデータ不整合楽観的ロックではダーティリードの発生を防ぐことが出来ますが、ファジーリード、ファントムリードは防ぐことができません。メリット悲観的ロックに比べてロック待ちが発生しない分、トランザクション完了までの時間は短くなります。行う必要がありません。相性が良いとされています。デメリット潜在的に、ロック待ちが発生しない分、不整合が発生する可能性が高まるデメリットが存在します。前提として更新が同時に行われる頻度が少ない環境を想定していることから、このデメリットは無視できます。発生などを実装する必要があります。マッパーを使う限りはこのデメリットも無視できます。まとめデータの不整合が発生した状態は多く存在し、トランザクションの分離レベルを可用性と効率とのトレードオフで選択する必要があることを紹介しました。おいて有効であると言えることを紹介しました。マッパーについて具体例を紹介していきたいと思います。仕事お役立ち情報SNSでもご購読できます。業界初のスキルオークション型採用サービス「SEROKU」SEROKUは、フリーランスエンジニアが働きやすい社会を実現するための新しいプラットフォームです。フリーランスと企業がダイレクトにスキルオークションを通して、ダイレクトに結びつくことで、現在、開発現場で発生している様々な課題(法律面、報酬面)を解決します。