まずはrailsのバージョン
$ bundle exec rails -v Rails 4.1.4
mysqlのテーブル
mysql> desc seq_sometest3s; +--------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+------------+------+-----+---------+-------+ | id | int(10) | NO | PRI | 0 | | | seq_id | bigint(10) | YES | | NULL | | +--------+------------+------+-----+---------+-------+ 2 rows in set (0.01 sec) mysql> select * from seq_sometest3s; +----+--------+ | id | seq_id | +----+--------+ | 1 | 100049 | +----+--------+ 1 row in set (0.00 sec)
まずネットで調べた以下のやり方だとエラーになりました。
tbl = base.find(1, lock: true) tbl.increment!(:seq_id) tbl.seq_id (0.2ms) BEGIN SeqSometest3 Load (0.7ms) SELECT `seq_sometest3s`.* FROM `seq_sometest3s` WHERE `seq_sometest3s`.`id` IN (1, '---\n:lock: true\n') (0.2ms) ROLLBACK
次に出てきた以下のやり方だとエラーは出ませんでした。
ただ、プライマリーキーで指定しているのでorder byが不要です、
tbl = base.where("id =1").lock(true).first tbl.increment!(:seq_id) tbl.seq_id (0.1ms) BEGIN SeqSometest3 Load (0.2ms) SELECT `seq_sometest3s`.* FROM `seq_sometest3s` WHERE (id =1) ORDER BY `seq_sometest3s`.`id` ASC LIMIT 1 FOR UPDATE SQL (0.2ms) UPDATE `seq_sometest3s` SET `seq_id` = 100046 WHERE `seq_sometest3s`.`id` = 1 (0.4ms) COMMIT
次のやり方でもエラーは出ませんでしたが、
order byはつかなくなったけど2回selectが実行されてしまいます。
後半のSQLだけでよいのに。
tbl = base.find(1).lock! tbl.increment!(:seq_id) tbl.seq_id (0.1ms) BEGIN SeqSometest3 Load (0.2ms) SELECT `seq_sometest3s`.* FROM `seq_sometest3s` WHERE `seq_sometest3s`.`id` = 1 LIMIT 1 SeqSometest3 Load (0.2ms) SELECT `seq_sometest3s`.* FROM `seq_sometest3s` WHERE `seq_sometest3s`.`id` = 1 LIMIT 1 FOR UPDATE SQL (0.2ms) UPDATE `seq_sometest3s` SET `seq_id` = 100047 WHERE `seq_sometest3s`.`id` = 1 (0.6ms) COMMIT
このやり方だとselectも1回しか発行されず、order byもつかないSQLが発行できました。
tbl = base.lock.find(1) tbl.increment!(:seq_id) tbl.seq_id (0.1ms) BEGIN SeqSometest3 Load (0.4ms) SELECT `seq_sometest3s`.* FROM `seq_sometest3s` WHERE `seq_sometest3s`.`id` = 1 LIMIT 1 FOR UPDATE SQL (0.3ms) UPDATE `seq_sometest3s` SET `seq_id` = 100049 WHERE `seq_sometest3s`.`id` = 1 (0.3ms) COMMIT
ちなみに存在しないレコードにロックをかけようとすると、
RecordNotFoundのエラーが出ました。
tbl = base.lock.find(2) tbl.increment!(:seq_id) tbl.seq_id (0.2ms) BEGIN SeqSometest3 Load (0.2ms) SELECT `seq_sometest3s`.* FROM `seq_sometest3s` WHERE `seq_sometest3s`.`id` = 2 LIMIT 1 FOR UPDATE (0.1ms) ROLLBACK ActiveRecord::RecordNotFound (Couldn't find SeqSometest3 with 'id'=2):
参考URL
http://apidock.com/rails/ActiveRecord/Locking/Pessimistic
http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html
0 件のコメント:
コメントを投稿