484
401

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RailsのTransactionの使い方

Last updated at Posted at 2014-11-27

#なぜTransactionが必要なのか
Transationの目的は、あるいコードブロックにあるSQL文の変更を、全部成功することを守るための存在である。Transactionにより、データの統一性を保ことができる。銀行などの受け入れと引き出しの処理には必要でしょう。二つの処理の中一つが失敗すると、コードブロークにあるSQL処理を全部ロールバックされるのが、Transactionの特徴である。

ActiveRecord::Base.transaction do
  david.withdrawal(100)
  mary.deposit(100)
end

#Transationのロールバックが発火条件
Railsでは、ロールバックが発火するには、「例外」が必要である。これがTransactionを使うときのもっとも重要なことである。

例えば、Railsでは #update_attributeは例外を発火せずに、falseに返すとなる。そのため、#update_attributeを使うには、結果を見て、例外をスローする必要がある。Railsではびっくりマーク!がついているメソッドは、失敗したら例外をスローすると意図するので、transactionを使うときは、saveではなくsave!destroyではなくdestroy!を使うべきでしょう。

例外が発生するときは、transactionがまず受け取って、ロールバックを行う。ロールバックが終わった後は、例外がそのまま外にスローされるため、アプリケーション側もその例外を対応する必要がある。

例外を使わずに、Transactionをロールバックさせたい場合は、ActiveRecord::Rollbackを使えばよい。ActiveRecord::Rollbackは外側にスローされないため、アプリケーション側は対応しなくてもいいという利点がある。

#いつNested Transactionを使うべき
Nested Transactionの例ですが:

User.transaction do
  User.create(username: 'Kotori')
  User.transaction do
    User.create(username: 'Nemu')
    raise ActiveRecord::Rollback
  end
end

Nested Transactionを使うときの最も重要な注意点は、一番中の処理がActiveRecord::Rollbackが投げても、子transactionで受け取った後広められず、親Transactionは受け取れないことである。広めたいときは、子transactionに :require_new => trueを設定する必要がある。

じゃいつNested Transactionを使うべきかの話ですが、マルチデータベースをマルチモデルで使うときは、メソッドをNested Transctionの中で囲まれる必要がある:

Client.transaction do
  Product.transaction do
    product.buy(@quantity)
    client.update_attributes!(:sales_count => @sales_count + 1)
  end
end

#Transactionsでのコールバック
もし#savedestroyがTransactionで使う場合、#after_saveもTransactionの中で実行されてしまう。そのため
Transactionの外で実行したい場合は、#after_commit#after_rollbackで実装してください。

#Transactionで細かいの注意点
Transactionの中で ActiveRecord::Invalidをしない方がよい。なぜなら、Postgresではその例外をキャッチしたら、囲まれるTransactionもロールバックされてしまう振る舞いがある。

#結論
Transactionを使うときのアンチパータン

  • シングルレコードを更新するときにTransaction使う
  • Nested Transactionを使いすぎる
  • Transactionにある処理がどうしてもロールバックを発火できない
  • ControllerでTransactionを使う

#参考資料
http://markdaggett.com/blog/2011/12/01/transactions-in-rails/

484
401
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
484
401

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?