トランザクション
transactionを利用して、一連の更新処理をアトミックに実行します。
トランザクションを使う
テーブル定義:
CREATE TABLE kittens ( id int(11) NOT NULL auto_increment PRIMARY KEY, name VARCHAR(255), color VARCHAR(255), age int(4) ) TYPE = InnoDB ;
サンプル:
# 接続先サーバーの設定は省略 # ロガーの設定/ログを"debug.txt"に出力する。 ActiveRecord::Base.logger = Logger.new("debug.txt") class Kitten < ActiveRecord::Base def to_s return name end end # transaction を利用。 # ブロック実行後に変更がコミットされる。 mii = Kitten.new kuro = Kitten.new Kitten.transaction { mii.name = "mii" kuro.name = "kuro" mii.save kuro.save } puts Kitten.find_by_name("mii") # =>mii puts Kitten.find_by_name("kuro") # =>kuro
出力:
mii kuro
ログを見ると、INSERTがBEGIN/COMMITで囲まれていることがわかります。
ログ(debug.txt):
... [4;35;1mSQL (0.000000) [0m [0mBEGIN [0m [4;36;1mSQL (0.015000) [0m [0;1mINSERT INTO kittens (`name`, `color`, `age`) VALUES('mii', NULL, NULL) [0m [4;35;1mSQL (0.000000) [0m [0mINSERT INTO kittens (`name`, `color`, `age`) VALUES('kuro', NULL, NULL) [0m [4;36;1mSQL (0.000000) [0m [0;1mCOMMIT [0m ...
トランザクションをつかわない
transactionを使用しない場合、更新が個別にBEGIN/COMMITされます。
サンプル(トランザクションを利用しない):
# transaction を利用しない。 # saveごとに個別にコミットされる。 mii = Kitten.new kuro = Kitten.new mii.name = "mii" kuro.name = "kuro" mii.save kuro.save
ログ:
... [4;35;1mSQL (0.000000) [0m [0mBEGIN [0m [4;36;1mSQL (0.016000) [0m [0;1mINSERT INTO kittens (`name`, `color`, `age`) VALUES('mii', NULL, NULL) [0m [4;35;1mSQL (0.000000) [0m [0mCOMMIT [0m [4;36;1mSQL (0.000000) [0m [0;1mBEGIN [0m [4;35;1mSQL (0.000000) [0m [0mINSERT INTO kittens (`name`, `color`, `age`) VALUES('kuro', NULL, NULL) [0m [4;36;1mSQL (0.000000) [0m [0;1mCOMMIT [0m ...
ロールバック
transactionブロック内で例外がスローされると、トランザクションはロールバックされます。
サンプル(ロールバック):
mii = Kitten.new kuro = Kitten.new Kitten.transaction { mii.name = "mii" kuro.name = "kuro" mii.save kuro.save } # ブロック内部で例外をスローすると、トランザクションがロールバックされる。 begin Kitten.transaction { mii.name = "mii.edit" kuro.name = "kuro.edit" mii.save kuro.save fail "test"# 例外をスロー } rescue p $! end puts Kitten.find_by_name("mii") # =>mii puts Kitten.find_by_name("kuro") # =>kuro
出力:
#<RuntimeError: test> mii kuro
ログ:
... [4;35;1mSQL (0.160000) [0m [0mCOMMIT [0m [4;36;1mSQL (0.010000) [0m [0;1mBEGIN [0m [4;35;1mKitten Update (0.020000) [0m [0mUPDATE kittens SET `age` = NULL, `color` = NULL, `name` = 'mii.edit' WHERE `id` = 3 [0m [4;36;1mKitten Update (0.000000) [0m [0;1mUPDATE kittens SET `age` = NULL, `color` = NULL, `name` = 'kuro.edit' WHERE `id` = 4 [0m [4;35;1mSQL (0.030000) [0m [0mROLLBACK [0m ...