ざっくりSQL入門 #11:トランザクション
※MySQLを前提に書いています。一部関数などは方言差がある場合もあるのでご注意ください。
今回はトランザクションについて。
トランザクションとは
「分けることのできない複数の処理をまとめた単位」です。
(データベースに限った意味合いではありませんが、以降、データベースについての話とします)
例えばどういうこと?
ひとつの処理に対して、複数のテーブルに対する更新が発生する場合があります。
例えば通販サイトの購入手続き時…
注文のメイン情報であるorderテーブル(order_id, user_id, name, address, ...)と
orderに紐づき、購入商品単位のデータをもつorder_productテーブル(order_id, product_id, count, price, ...)
の2つがあるとします。
注文が発生すると、それぞれのテーブルにINSERTが発生することになります。
order
order_id | user_id | name | address | ... |
51088 | 43109 | 鈴木太郎 | 東京都新宿区... | ... |
order_product
order_id | product_id | count | price | ... |
51088 | 101 | 2 | 2000 | ... |
51088 | 102 | 5 | 5000 | ... |
このとき、orderへのINSERTは成功し、order_productへのINSERTは失敗してしまうと、
orderにだけ中途半端なデータが残ってしまうことになります。
それでは困る、というときに、この2つのINSERTをまとめてひとつのトランザクションにするのです。
具体的にはどう書くの?
トランザクションの開始時に「BEGIN(もしくは START TRANSACTION)」
トランザクションの正常終了時に「COMMIT」
トランザクションを全部取り消したいときに「ROLLBACK」です。
COMMITを書いていない場合や途中でエラーになった場合は、
ROLLBACKを明示しなくとも全部取り消されます。
BEGIN; INSERT INTO `order` VALUES ... INSERT INTO `order_product` VALUES ... COMMIT;
SQLを手打ちするだけならROLLBACKを使うことはそうそうないのですが、
アプリケーションで実装する場合は例えば以下のようなパターンが実現できます。
// UPDATEを行うが、 // その結果が1件以下ならそのUPDATEを取り消し、 // 2件以上なら別のテーブルにもINSERTを行う BEGIN; UPDATE `hoge` SET ... ; if ( /* UPDATEの結果が1件以下 */ ) { ROLLBACK; } else { INSERT `fuga` ... ; COMMIT; }
暗黙的なコミットについて
「TRUNCATE TABLE」など一部の構文については、コミットが発生してしまうため注意が必要です。
過去に詳しく書いていますのでリンクにとどめておきます。
トランザクションの挙動検証 - アナログCPU:5108843109