Help us understand the problem. What is going on with this article?

RailsのTransactionの使い方

More than 3 years have passed since last update.

なぜ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/

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした