アナログCPU:5108843109

ゲームと音楽とプログラミング(酒と女とロックンロールのノリで)

('ω') < イザユケエンジニャー

ざっくり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