トランザクション

トランザクション

執筆済 ソフトウェア開発データベース

複数の操作をひとまとまりとして扱う。 全部成功するか、全部無かったことになるか。

sql
BEGIN;
  UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
  UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
COMMIT;

片方だけ実行されると、お金が消える。

並行実行の問題#

現象 内容
ダーティリード コミットされていない変更を読む
反復不能読み取り 同じ行を 2 回読んで値が違う
ファントムリード 同じ条件で 2 回読んで行数が違う
更新の喪失 2 つの更新のうち片方が消える
書き込みスキュー 個別には正しいが、合わせると制約違反

分離レベル#

レベル ダーティ 反復不能 ファントム
READ UNCOMMITTED 起きる 起きる 起きる
READ COMMITTED 防ぐ 起きる 起きる
REPEATABLE READ 防ぐ 防ぐ 起きる※
SERIALIZABLE 防ぐ 防ぐ 防ぐ

※ PostgreSQL の REPEATABLE READ(スナップショット分離)は ファントムも防ぐが、書き込みスキューは防がない。

分離レベルは正しさと性能のトレードオフ。 既定は PostgreSQL が READ COMMITTED、 MySQL (InnoDB) が REPEATABLE READ。 製品によって既定も意味も違うので確認が要る。

MVCC#

多版型同時実行制御。 行を上書きせず新しい版を作る

読み手 … 自分が開始した時点の版を読む
書き手 … 新しい版を作る

読みが書きをブロックせず、書きが読みをブロックしない。 これが現代の DB の高い並行性を支えている。

代わりに古い版の掃除(PostgreSQL の VACUUM)が要る。

デッドロック#

複数のトランザクションが互いのロックを待つ。 DB は検出して片方を中断する。

一般論と同じく、 アクセス順序を揃えるのが最も有効な対処。

参考文献#

ノート一覧を閉じる