共有ロック、占有ロック、またデッドロックと回避策についても具体例を挙げながら説明します。
特に新人システムエンジニアやプログラマーに抑えておいて欲しい内容です。
この記事を書いている僕はシステムエンジニア6年目 普段はJavaでWebアプリを作ったりSQL書いたり・・(DBAのような仕事は普段していないです)
応用情報技術者試験に合格(2回落ちましたが。。)し、データベースの分野が得意だったので、独学でデータベーススペシャリストの勉強をして、昨年合格(これは1発合格)しました。
今回は、トランザクション管理機能の1つである排他制御機能についてまとめました。
この記事を読む前に
以下の記事を読んでトランザクションについて理解しておくのがオススメです。

排他制御
複数のトランザクションを自由に同時に実行させると、、、
同じテーブルに対して同時に更新や参照を行ってしまい個々のトランザクションが他のトランザクションに影響を与え、タイミングによっては誤った結果になってしまいます。
それを回避するためにDBMSでは並列実行されているトランザクションを直列実行可能(直列実行可能性)になるように制御しています。
この時に行っている制御が排他制御です。
直列実行可能性(serializable)
2つのトランザクションT1、T2がT1→T2、T2→T1のどちらの順に実行されても同じ結果になる場合、直列実行可能性が保証されているという。
占有ロックと共有ロック
排他制御は主に、データベースのロックによって実現しています。
ロックとは更新や参照する対象データに鍵をかけて他のトランザクションからアクセスできないようにすることです。 また、ロックには占有ロックと共有ロックの2種類があります。
共有ロック
一般的にトランザクションがデータを参照する前に共有ロックを実施します。
また、共有ロックがかかっている場合、他のトランザクションからは該当データに対して共有ロックはかけれるが、占有ロックはかけれない。
つまり、共有ロック中、他のトランザクションから該当データを参照できるが、更新できない。
占有ロック
一般的にトランザクションがデータを更新する前に占有ロックを実施します。
また、占有ロックがかかっている場合、他のトランザクションからは対象データに対して共有ロック、占有ロック共にかけれない。
つまり、占有ロック中、他のトランザクションからは該当データを参照、更新できない。 これらを表にまとめると以下のようになります。
また、ロック対象となるデータの単位をロックの粒度と言います。
粒度には行、テーブル、ページ、テーブル、データベースなどがあり、 例えばロックの粒度が行の場合トランザクションは同時に同じテーブルを参照、更新することは可能です。
ロックの粒度がテーブルの場合には同じテーブルにアクセスするにはロックが解除されるまで待つ必要があります。
デッドロック
2つのトランザクションが互いの処理に必要な資源をロックし合っているために、処理が続行できなくなった状態のことをデッドロックと言います。
例えば上の例の場合、
在庫変更トランザクション「3.占有ロック」をしようとするが既に商品名変更トランザクション「2.占有ロック」でロック解放待ちとなり、
商品名変更トランザクション「4.占有ロック」をしようとするが既に在庫変更トランザクション「1.共有ロック」でロック解放待ちとなります。
このような状態がデッドロックです。
デッドロックになった場合、 大抵DBMSが一定時間ロック待ちになっているトランザクションを検出してタイムアウトエラーで落としてくれます。
また、ここでは説明を省略しますが、待ちグラフというものを利用してデッドロックを検出することもできます。
デッドロックの回避
デッドロックを回避するには、 各トランザクションの資源ロックの順番を同じにすれば良いです。
このようにトランザクション内の処理の順番を変更させてデッドロック回避させる問題は、よくデータベーススペシャリストの午後問題で出ます!!!
例えば上の例の在庫変更トランザクションの資源ロックの順番を変更すると、
在庫変更トランザクションの資源ロックの順番を変更することで、待ちが発生してもトランザクション完了によってロックが解放されるのでデッドロックを避けることができます。
まとめ
今回はトランザクション管理機能の排他制御について確認しました。
データベーススペシャリストの試験の午後問題ではある2つのトランザクションが同時に実行された時に起こり得る問題について説明させられたり、またそれを解決するためにはどうすれば良いかを問われることがあります。
また、現場でシステム開発をする際、
利用しているDBMSのロックの粒度は行ロックなのか?テーブルロックなのか?(おそらく行ロックでしょうが、、)を調べてみたり、 ロック解放待ちの上限時間は何秒なのかを調べてみると面白いかも。。。
最後に、デッドロックではないですが、、、
DBMSにデッドロックとみなされてエラーとなってしまったケースを体験したことがあるので紹介します。
「あるユーザが一括更新処理実行中(処理に10分くらいかかる)に、別のユーザが一括更新の処理対象のうちの1つのデータを更新しようとしてロック待ちとなり、ロック解放待ち上限時間を超えてDBMSからエラーが返される。(DBMSは行ロック)」
オンライン処理で10分もかかるような一括更新処理を許容しているシステムに問題ありな気がしてましたが、、
皆さんは気をつけてください。