データベース

【基本情報】データベースの排他制御とデッドロックについて解説

お茶ん太
お茶ん太

この記事では、排他制御とデッドロックについて、初心者にも分かりやすく図解付きで丁寧に解説しています!

トランザクション処理

  • トランザクション処理とはデータベースに対してまとめて処理する必要がある操作を一括りにした処理。
  • トランザクション処理はお互いに干渉せず、独立して実行する必要がある。これを独立性と呼ぶ。

排他制御

  • トランザクション処理を実行している間、別のトランザクション処理が実行できないようにデータベースをロックする必要があり、これを排他制御と呼ぶ。
  • 専有ロック中、他トランザクションはデータの更新も読取も出来ない。
  • 共有ロック中、他トランザクションはデータの更新は出来ないが、読取は出来る。

デッドロック

  • デッドロックとは、複数のトランザクションがお互いに使いたいテーブルをロックしてしまい、永遠にお互いのロック解放待ち状態になること。
  • デッドロックを防ぐには、複数のトランザクションが同じ順番でテーブルにアクセスする必要がある。

トランザクション処理

トランザクション処理とは、データベースに対してまとめて行う必要がある操作を一括りにした処理のことです。トランザクション処理は全てを完全に行うか、全く行わないかのどちらかです。

トランザクション処理の例は銀行の振込処理です。
振込処理は以下の4つの処理から成り立ち、中断することは許されません。

  1. Aさん(送金する人)の口座残高を確認する
  2. Aさんの口座から残高を減らす
  3. Bさん(入金される人)の口座残高を確認する
  4. Bさんの口座残高から残高を増やす

トランザクション処理が途中で終了した場合を考えてみましょう。例えば、送金口座から残高を減らした後にシステム障害が起きて、入金口座の残高を増やす処理が行われなかったとします。Aさんの送金口座からお金は減ったのに、Bさんの入金口座の残高が増えないことになり、凄く困ったことになりますよね。

なので、処理を行う時は4つ全て行う必要があり、途中で失敗した時は一番最初の状態に戻す必要があります。このように、一連で行う必要がある操作の一括りをトランザクション処理と言います。トランザクション処理はACID特性と呼ばれる4つの性質を満たす必要がありますが、ここでは排他制御に関係する独立性だけ紹介します。他の性質も大切なので、自信が無い方はこちらの記事を確認してください。

【基本情報】トランザクション処理とコミット・ロールバックについて解説 トランザクション処理 トランザクション処理とはデータベースに対してまとめて処理する必要がある操作を一括りにした処理...

トランザクション処理の独立性

複数のトランザクション処理を実行する際、それぞれが干渉せずに独立して実行される必要があるという性質を独立性と呼びます。

例えば、残高が1000円あるときに、100円の銀行引き落としと200円の銀行引き落としが同時に実行されたとします。この時、1000円-100円=900円の処理と900円-200円=700円の処理がそれぞれ独立して行われる必要があります。つまり残高は700円になるということですね。

同時に行われたから、1000円-100円=900円、1000円-200円=800円で計算して残高が800円になりました。では困りますよね。

このようなトランザクション処理は1つずつ完了させる必要があるという性質が独立性になります。

排他制御

トランザクション処理では独立性を満たす必要があるため、トランザクション処理を行っている時は別のトランザクション処理が実行出来ないようにデータベースをロックします。これを排他制御と言います。

排他制御をしないとどうなるのか

排他制御を行わずに、複数のトランザクション処理を行うとどうなるのでしょうか。ATMからお金を引き出すトランザクションを同時に行った場合を考えてみます。

ATMからお金を引き出すトランザクションでは以下3つの処理を行います。

  1. 口座残高を確認する
  2. 口座残高からお金を減らす
  3. ATMからお金を出金する

今、残高が100万円の口座から1万円を引き出す処理を同時に行ってみます。

  1. トランザクション①が残高を確認する:残高100万円であると確認
  2. トランザクション②が残高を確認する:残高100万円であると確認
  3. トランザクション①で残高を1万円減らす:100万円から1万円減らして99万円にする
  4. トランザクション②で残高を1万円減らす:100万円から1万円減らして99万円にする
  5. トランザクション①で1万円を出金
  6. トランザクション②で1万円を出金

トランザクション①と②で合計2万円出金しているのに銀行の残高は99万円と、おかしなデータが発生しています。

排他制御をするとどうなるか

排他制御を行うと、トランザクション実行中はデータベースをロックして別のトランザクションがアクセス出来ないようにします。

  1. トランザクション①が残高を確認する:残高100万円であると確認
  2. トランザクション①で残高を1万円減らす:100万円から1万円減らして99万円にする
  3. トランザクション①で1万円を出金
  4. トランザクション②が残高を確認する:残高99万円であると確認
  5. トランザクション②で残高を1万円減らす:99万円から1万円減らして98万円にする
  6. トランザクション②で1万円を出金

トランザクション①実行中はデータベースをロックしているので、トランザクション②はデータベースにアクセス出来ません。そのため、トランザクション①→トランザクション②の順番で実行することになり、データの整合性が保たれます。

専有ロックと共有ロック

データベースにおかしなデータを生み出さないためには排他制御をする必要があることが分かりました。では、排他制御の際、どのようにデータベースをロックするのでしょうか。ロックの方法はトランザクション処理のタイプによります。

2種類のトランザクション処理

トランザクション処理には大きく分けて2種類あります。

  1. 登録・更新・削除など、データを変更する処理
  2. データを変更せずに読み取るだけの処理

口座への入金や出金はデータを変更する処理ですが、残高や取引履歴を確認するのは読み取り処理になります。トランザクション処理の種類によって、排他制御のロックの仕方が変わります。

専有ロック

データを変更する処理の場合は専有ロックを行います専有ロックを行うと、後続のトランザクションはデータを変更する処理もデータを読み取る処理も行えません

データ変更中に別のトランザクション処理がデータを変更するとおかしなデータが出来てしまいます。また、データを読取っても変更中のデータを読取ることになるので誤解を生む可能性があります。なので、専有ロック中は変更も読取も不可になります。

共有ロック

データを読取る処理の場合は共有ロックを行います共有ロックを行うと、後続のトランザクションはデータを変更する処理は出来ませんが、データを読み取る処理は行えます

データ読取中に別のトランザクション処理がデータを変更すると、変更中のおかしなデータを見ることになってしまいます。しかし、データ読取中に別のトランザクションがデータを読取る分にはデータの不整合は発生しないので問題ありません。なので、共有ロック中は変更不可で読取可能になります。

デッドロック

デッドロックとは、複数のトランザクション処理が同じデータベースを使用する場合に、お互いに相手がアクセスしたいデータベースをロックしてしまい、永遠に待ち状態になってしまう状態のことです。

下の例では、トランザクション①がテーブルA→テーブルBの順番で、トランザクション②がテーブルB→テーブルAの順番で編集しようとしているため、お互いがお互いロックしているテーブルの解放待ちになってしまい、次のステップに進めなくなっています。この状態がデッドロックです。

アクセスする順番が逆のトランザクション処理が存在すると、デッドロックが発生する可能性があるため、複数のトランザクション処理を実行する場合は同じ順番でアクセスするように設計します。上の例で言うと、トランザクション①・②の両方がテーブルA→テーブルBもしくはテーブルB→テーブルAの順番でアクセスする設計になっていればデッドロックは起きなかったということですね。

基本情報技術者試験での出題例

令和元年度秋期問29

基本情報技術者
午前試験 令和元年度秋期問29

2相ロッキングプロトコルに従ってロックを獲得するトランザクションA,Bを図のように同時実行した場合に,デッドロックが発生しないデータ処理順序はどれか。ここで,read と update の位置は,アプリケーションプログラムでの命令発行時点を表す。また,データWへの read は共有ロックを要求し,データX,Y,Zへの update は各データへの専有ロックを要求する。

正解と解説

正解は”ウ”

データWへのアクセスは共有ロックを要求するため、ここでデッドロックは発生しません。
なので、データX,Y,Zへの専有ロックでデッドロックが起こらないパターンを考えます。

専有ロックは同じ順番でアクセスすれば起こりません。トランザクションAと同じ順番でデータにアクセスしているのは選択肢ウなのでウが正解です。

平成30年度秋期問29

基本情報技術者
午前試験 平成30年度秋期問29

ロックの粒度に関する説明のうち,適切なものはどれか。

ア データを更新するときに,粒度を大きくすると,他のトランザクションの待ちが多くなり,全体のスループットが低下する。

イ 同一のデータを更新するトランザクション数が多いときに,粒度を大きくすると,同時実行できるトランザクション数が増える。

ウ 表の全データを参照するときに,粒度を大きくすると,他のトランザクションのデータ参照を妨げないようにできる。

エ 粒度を大きくすると,含まれるデータ数が多くなるので,一つのトランザクションでかけるロックの個数が多くなる。

正解と解説

正解は”ア”

ロックの粒度とは、トランザクション実行時にどこまでロックするかを決める単位です。
編集対象の行だけロックするのか、表ごとロックするのか、データベースごとロックするのかを決めます。

ア スループットとは処理時間のことです。1つのトランザクションがロックするものが大きいと、他のトランザクションの待ちが長くなるため、スループットは低下します。

イ ロックの対象を増やすと、同時実行できるトランザクションは減少します。

ウ ロックの粒度を大きくすると、他のトランザクションの妨げになります。

エ 1つ1つのトランザクションのロックの粒度を大きくすると、同時実行出来るトランザクションは減るため、ロックの数自体は少なくなります。

平成30年度春期問30

基本情報技術者
午前試験 平成30年度春期問30

RDBMSのロックの粒度に関する次の記述において,a,bの組合せとして適切なものはどれか。

並行に処理される2つのトランザクションがそれぞれ一つの表内の複数の行を更新する。行単位のロックを使用する場合と表単位のロックを使用する場合とを比べると,ロックの競合がより起こりやすいのは『 a 』単位のロックを使用する場合である。また,トランザクション実行中にロックを管理するためのRDBMSのメモリ使用領域がより多く必要になるのは『 b 』単位のロックを使用する場合である。

正解と解説

正解は”ウ”

トランザクション処理を実行する際、ロックをする対象が大きければ大きいほど、他のトランザクション処理の待ちが発生しやすくなります。これをロックの競合と言います。

表と行では、表の方が大きい単位になるので、表単位のロックを使用した場合の方がロックの競合は発生しやすくなります。

しかし、複数行を編集するようなトランザクション処理を実行する場合、行1つ1つをロックするのと、複数行全部を含む表を一括でロックするのを比べると、表を一括でロックする方がロジックが単純です。なので、ロックを管理するために必要なメモリも少なくて済みます。