2014年9月29日月曜日

Rails4で複数モデルのトランザクションについて調べてみた

仕事で最近rais4を使って開発してるんだけど、トランサクションについてわからんのでちょっと調べてみた。


必要な仕様としては、インサートする配列があって、どこかでインサートがこけたらrollbackして成功していたインサートもなかったことにする。


自分これ系の仕様嫌いなんだけど。。。
しょうがないからやってみた。


まず、バルクインサートさせるために「activerecord-import」を使う。
Gemfileに下記を記述して
gem 'activerecord-import'

bundle update


で、mysqlでテーブル3つ用意。
foodsテーブル
order integer not null
name  string

jobsテーブル
order integer not null
name  string


likeテーブル
order integer not null
name  string


どれも構成はおんなじ。
ネーミングセンスはテストなので気にしないでちょ(汗)
データはあらかじめ入れておくよ。


簡潔にテストしたいのでスタティックなコントローラに下記を記述。
orderはnot nullなのでorderのところに「nil」を入れておいて、わざとエラーにさせる。


コントローラに書くコードは下記のコード。

p '------------------------'
ng=[
  { :order => 10, :name => 'ああああ'},
  { :order => 11, :name => 'えええ'},
  { :order => nil, :name => 'いいい'},
  { :order => 13, :name => 'ううう'},
  { :order => 14, :name => 'おおお'},
]

ok=[
  { :order => 10, :name => 'ああああ'},
  { :order => 11, :name => 'えええ'},
  { :order => 12, :name => 'いいい'},
  { :order => 13, :name => 'ううう'},
  { :order => 14, :name => 'おおお'},
]

j = []
ng.each do |i|
   j << Job.new(i)
end

f = []
ok.each do |i|
   f << Food.new(i)
end

begin
  Job.transaction do
    Food.import f
    Job.import j
   
    a = Like.where(Like.arel_table[:order].lteq(10))
    a.update_all({:name => 'きゃー'})
  end
rescue ex
  p '----------- error -------'
  p ex.messages
end

どっかの記事でRails(4)は複数のトランザクションをサポートしない。。。
みたいな記事を見たんだけど、構わず無作為にピックアップしたモデルを使ってトランザクションしてみる。


実行してみた結果、クエリがこけたときは見事rollbackされることが確認できた。
どのテーブルも更新されませんでした。
念のため、Food, Job, Likeでそれぞれこけさせてみたが、結果は同じ更新されてませんでした。
もちろん、成功時は三つのテーブルに更新がかかっているのも確認ができた。


モデル.transaction doで複数のモデルの更新管理ができることはわかったけど、Rails自身がバージョンアップしたら動かなくなる可能性もあるので注意かも?

0 件のコメント:

コメントを投稿