トランザクションとACID特性とは ― 排他制御の基本
トランザクションは、
トランザクションとは、複数の処理をまとめて1つの単位にしたもの
トランザクションとは、データベースへの複数の処理をまとめて、1つの単位として扱う仕組みです。単位の中の処理は、すべて反映されるか、すべて取り消されるかのどちらかになります。一部だけ反映された状態にはなりません。
例えば、口座Aから口座Bへ送金する処理を考えます。口座Aから1万円を引く処理と、口座Bに1万円を足す処理の、2つのSQL文が必要です。この2つを1つのトランザクションにまとめておけば、途中で故障が起きても、両方取り消されます。
口座Aから引く処理だけが反映されると、1万円がどこにも存在しない状態になります。DBMSは、この矛盾を防ぐ機能を持っています。その中心になるのが、排他制御とACID特性です。
排他制御(同時実行制御)とは、同時更新による矛盾を防ぐ仕組み
排他制御とは、複数のトランザクションが同時に同じデータを更新しても、矛盾が起きないようにする仕組みです。同時実行制御と呼ぶこともあります。代表的なやり方が、ロック方式です。
ロックとは、あるトランザクションが使っているデータに付けて、他のトランザクションの操作を制限する印です。ロックが許可されないとき、後から来たトランザクションは、先にロックを取った側の処理が終わるまで待たされます。
ロックが無いと、両方のプログラムが古い在庫数を読んでから書き込むので、片方の更新が消えてしまいます。ロックがあれば、先に読んだ側の処理が終わるまで、もう片方は待たされます。その結果、2回分の更新が両方反映されます。
ロックには、データを読むだけのときに使う共有ロックと、データを書き換えるときに使う専有ロックがあります。共有ロックは、他の共有ロックと同時に許可されます。専有ロックは、他のどのロックとも同時には許可されません。
| 種類 | 許可される | 向く |
|---|---|---|
| 共有ロック | 他の共有ロックとは同時に許可される | データを読むだけの処理 |
| 専有ロック | 他のどのロックとも同時に許可されない | データを書き換える処理 |
図の在庫の例では、読んだ値をもとに書き換えるので、読む時点から専有ロックを取ります。共有ロックでは、もう片方も同時に在庫を読めてしまうためです。読む時点で先にロックを取るこのやり方と、ロックを取らずに更新の時点で衝突を見つけるやり方の違いは、楽観ロックと悲観ロックの記事で比べています。
ロックを取る範囲の大きさを、ロック粒度と呼びます。表全体をロックすると他の処理を長く待たせますが、管理は簡単です。行単位でロックすると待たせる範囲は狭くなりますが、管理する情報が増えます。
複数のトランザクションが互いのロックの解放を待ち合い、どちらも先に進めなくなることがあります。この状態をデッドロックと呼びます。デッドロックが起きる仕組みと検知後の対処は、排他制御とデッドロックの記事で詳しく説明します。
ACID特性とは、トランザクションに求められる4つの性質
ACID特性とは、トランザクション処理に求められる4つの性質です。原子性・一貫性・独立性・永続性の4つを指します。複数の利用者が同時にデータベースにアクセスしても、データを矛盾させないために必要です。
トランザクションの中の複数の処理は、すべて反映されるか、すべて取り消されるかのどちらかになります。一部だけ反映された状態にはなりません。
トランザクションの前後で、データベースが決めたルール(一意性制約や参照制約など)に違反しません。違反する更新は、コミットされずに取り消されます。
コミットが終わるまで、トランザクションの途中の変更は、他のトランザクションから見えません。この性質は、主にロックなどの仕組みで守られます。
コミットが終わった変更は、その後に停電やシステム障害が起きても失われません。変更内容をログとしてディスクに書き込むことで、この性質を保ちます。
4つの性質は、互いに支え合っています。独立性は、主にロックなどの仕組みで支えられます。独立性をどこまで厳しく守るかは、分離レベルという段階で選べます。原子性と永続性は、次に説明するコミットとロールバック、そしてログの仕組みで支えられます。
コミットとロールバックが、原子性と永続性を支える
コミットとは、トランザクションの中の変更を、データベースに確定させる操作です。コミットが終わると、その変更は失われません。これが、永続性にあたります。
ロールバックとは、トランザクションの中の変更を取り消す操作です。そのトランザクションが行った変更は、すべて取り消されます。表の変更をきっかけに動くトリガが行った変更も、同じトランザクションに含まれるので一緒に取り消されます。コミットとロールバックのどちらかで終わる点が、原子性にあたります。WHEREを付け忘れたDELETE文をROLLBACKで取り消す例は、INSERT・UPDATE・DELETE文の記事で見られます。
トランザクションが保持していたロックは、コミットまたはロールバックが終わると解放されます。ロックが解放されるまで、他のトランザクションは待たされたままです。PostgreSQLでは、WITH HOLDを付けずに開いたカーソルも、このとき閉じられます。データベースが複数のサイトに分かれているとき、全サイトでコミットをそろえる仕組みは分散データベースの記事で説明しています。
障害回復とは、バックアップとログで矛盾のない状態に戻す仕組み
障害回復とは、停電や機器の故障が起きても、矛盾のない状態にデータベースを戻す仕組みです。障害に備えるバックアップの方式と、故障後に元に戻すリカバリ処理の2つに分かれます。
DBMSは、データを書き換えるたびに、その内容をジャーナルファイル(ログファイル)に記録しています。故障が起きたとき、このログをもとに、障害発生直前の状態まで戻します。
ディスクの故障などでデータが失われた場合は、まずバックアップからデータを戻します。そのうえで、コミットされた変更をログから再現します。この処理を、ロールフォワード(フォワードリカバリ)と呼びます。
コミットされていなかった変更をログから取り消す処理を、ロールバック(バックワードリカバリ)と呼びます。この2つを使い分けて、矛盾のない状態に戻します。障害の種類やチェックポイントの位置で、どちらを使うかを決める手順は、ロールフォワードとロールバックの記事で説明しています。戻す元になるバックアップの取り方は、フル・差分・増分バックアップの記事で比べています。
参考にした資料
練習問題(全5問)
正解:複数の
トランザクションは、
正解:独立性
独立性
正解:片方の
ロックが
正解:他の
専有ロックは、
正解:ジャーナルファイル
ジャーナルファイル
選んでから「採点する」を押すと、解説つきで答え合わせができます。
関連記事
おすすめの本 PR
セキュリティとデータベースは、基本情報技術者試験の対策本でまとめて学べます。

