🖥
#Rails + #MySQL / Transaction と INSERT RECORD と ROLLBACK で排他制御の実験
パターン1 - プロセスA
INSERTのあと、しばらく後続の処理が続くが、最後には失敗するケース
Transaction内の処理が失敗してロールバックする
ActiveRecord::Base.transaction { User.create!(unique_id: 'X1'); sleep 15; raise; }
# (0.7ms) BEGIN
# User Create (0.9ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('X1', '2020-01-09 08:18:34')
#
# ... wait ...
#
# (10.4ms) ROLLBACK
# from (pry):14:in `block in <main>'
パターン1 - プロセスB
プロセスAのTransaction内での処理と重複するレコードをINSERTする
プロセスAの処理が失敗するのを待ってからコミットされ、さらに後続の処理が開始・成功する
ActiveRecord::Base.transaction { User.create!(unique_id: 'X1'); puts 'OK!'; }
#
# (0.5ms) BEGIN
#
# ... wait ...
#
# User Create (2573.1ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('X1', '2020-01-09 08:18:41')
# OK!
# (9.4ms) COMMIT
# => nil
パターン2 - プロセスA
INSERTのあと、しばらく後続の処理が続いて、最後に成功するケース
ActiveRecord::Base.transaction { User.create!(unique_id: 'X2'); sleep 15; puts 'OK!'; }
# (1.0ms) BEGIN
# User Create (2.2ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('X2', '2020-01-09 08:22:14')
#
# ... wait ...
#
# OK!
# (19.2ms) COMMIT
# => nil
パターン2 - プロセスB
プロセスAの処理が成功するまで INSERT は待ち受け状態になる
プロセスAの処理が成功してTransactionが終了すると、こちらのINSERTはユニーク制限に反することが確定するため、そのタイミングで処理が失敗する
INSERT より後続の処理は実行されない
ActiveRecord::Base.transaction { User.create!(unique_id: 'X2'); puts 'OK!'; }
#
# ... wait ...
#
# (0.6ms) BEGIN
# User Create (6831.2ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('X2', '2020-01-09 08:22:22')
# (5.2ms) ROLLBACK
# ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry 'X2' for key 'index_users_on_unique_id': INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('X2', '2020-01-09 08:22:22')
パターン3 - プロセスA
他のパターンと同じく、INSERTの後にしばらくTransaction内の処理が続く
ActiveRecord::Base.transaction { User.create!(unique_id: 'X3'); sleep 15; puts 'OK!'; }
パターン3 - プロセスB
プロセスAのTransaction内での処理とは重複しないレコードをINSERTする
ユニーク制限に弾かれない登録なので、すぐコミットされる
ActiveRecord::Base.transaction { User.create!(unique_id: 'Y1'); puts 'OK!'; }
# (0.8ms) BEGIN
# User Create (0.9ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('Y1', '2020-01-09 08:18:38')
# OK!
# (2.9ms) COMMIT
# => nil
Original by Github issue
チャットメンバー募集
何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。
公開日時
2020-01-10
Discussion