消えた30万円
大阪の部品商社「浪速商事」が、名古屋の取引先に300,000円を払います。
振込では、2つのことが起きます。浪速商事の残高が減り、相手の残高が増えます。
もし、1つ目の後でサーバーが止まったらどうなるでしょう。お金は減ったのに、相手には届いていません。30万円が消えてしまいます。
このレッスンのゴール
メモ
振込が「全部か、何もしないか」でなければならない理由を、説明することができる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| トランザクション | ひとまとまりで扱う書き込みの組です。 | |
| BEGIN | トランザクションを始めます。 | |
| COMMIT | 変更を確定して、残します。 | |
| ROLLBACK | BEGIN からの変更を、すべて取り消します。 | |
| UPDATE | 行の値を書きかえる命令です。 | UPDATE accounts SET balance = 0 |
学生が入力するセルは、このプレビューでは空白です。
2つの書き込みは1つの仕事
振込は、「引く」と「足す」の2つの書き込みでできています。
片方だけが残ると、帳簿が合わなくなります。引いただけならお金が消え、足しただけならお金が増えます。
だから、この2つは1つの仕事として扱います。両方とも残るか、どちらも残らないか。この組をトランザクションといいます。
例: 途中で止まると帳簿が合わない
| 場面 | 浪速商事 | 中部金型製作所 | 合計 |
|---|---|---|---|
| 振込の前 | 800,000円 | 200,000円 | 1,000,000円 |
| 引いた後に停止 | 500,000円 | 200,000円 | 700,000円 |
| 両方とも完了 | 500,000円 | 500,000円 | 1,000,000円 |
| 両方とも取り消し | 800,000円 | 200,000円 | 1,000,000円 |
学生が入力するセルは、このプレビューでは空白です。
BEGINで始め、COMMITで確定する
BEGIN から後の書き込みは、まだ仮の状態です。
COMMIT を実行したとき、はじめて全部の変更が確定します。COMMIT の前にサーバーが止まったら、データベースは変更をなかったことにします。
こうして、途中の状態が残らないようにしています。
試そう: 振込を確定する
-- 浪速商事が、中部金型製作所に300,000円を払います。
BEGIN;
UPDATE accounts SET balance = balance - 300000 WHERE id = 1;
UPDATE accounts SET balance = balance + 300000 WHERE id = 2;
COMMIT;
-- 2つの残高が変わり、合計は1,000,000円のままです。
SELECT owner, balance FROM accounts;
SELECT SUM(balance) AS total FROM accounts;
ROLLBACKで全部を取り消す
途中で問題が見つかることもあります。入金先の口座番号が違う、残高が足りない、といった場合です。
そのときは ROLLBACK を実行します。BEGIN から後の変更が、すべて取り消されます。
次のブロックでは、1つ目の書き込みの後で取り消しています。
試そう: 途中で取り消す
-- 同じ振込で、途中で問題が見つかった場合です。
BEGIN;
UPDATE accounts SET balance = balance - 300000 WHERE id = 1;
-- ここで、システムが入金先の口座の誤りに気づき、取り消します。
ROLLBACK;
-- 浪速商事の残高は800,000円のままです。
SELECT owner, balance FROM accounts;
-- ROLLBACK を COMMIT に変えて実行してください。300,000円はどこへ行きましたか。
よくある間違い
注意
「COMMITした後でも、ROLLBACKで戻せる」と思う人がいます。戻せません。ROLLBACK が取り消せるのは、まだ確定していない変更だけです。確定した振込をまちがえたときは、逆向きの振込を新しいトランザクションで行います。
プログラムでも同じ決まり
アプリのプログラムでも、考え方は同じです。
足りるかどうかを先に確かめ、それから動かします。先に減らしてから確かめると、断ったときに、減った数が残ってしまいます。
次の課題は、大阪倉庫から神戸倉庫への在庫の移動です。関数の名前などは英語で、コメントは日本語で書いています。