きっかけ
- 働いていた時、特にコード規約がなく、いろんな人が触ったコードだったためか、いろんな書き方がされていた
- 複数のレコードを同時にsaveする時に、使うのは知っている
- ただベストプラクティスはどうなのかをちゃんと考えたことなかったので見てみる
学んだこと
そもそもエラーハンドリングの心得から勉強してみる
- こちらの記事がとても勉強になった
- Ruby on Railsを使って、大事なところを簡潔に書いてくれていてありがたい
- アンチパターンと、その場合どうすべきかが書かれている
- 運用のことを考えると、以下の2つの内容はすごく重要だったな。。
特別な理由がない限り、エラー情報を破棄してはいけない。 最悪の場合、エラーの原因を特定できなくなる。
エラー処理も必ずテストすること。 「たぶん動くはず」でそのままコードをリリースしてしまうと、最悪の場合「エラー処理のバグによるエラー」が発生してしまい、元のエラー内容が失われてしまう場合がある。(二重障害) こうなるとエラーの原因を調査するのが非常に難しくなる。
Railsのトランザクションはどう使うのか?
- 上記の記事の最後の項目が今回の内容に近い
- 基本的な書き方はRailsガイドを確認
- これらをみるとわかるように、
.transaction
をつけた場合は、.save
を通った瞬間DBにcommitされるわけではなく、ブロックを抜けた瞬間にDBにコミットされる- つまりコミットタイミングをコントロールしている
. lock
や.with_lock
を使うことで、同じレコードを書き込まないようにすることもできる- この時はdeadlockが発生しないような処理にする
ふと思い出した他の書き方
- 昔やってた時に、モデルに対して
.transaction
をかけただけでなく、以下のような書き方もしてたな〜と
ActiveRecord::Base.transaction do # データを作るような処理とsave end
- 要は同じ処理で得られる結果は同じ
ActiveRecord::Base
は各モデルの親クラスであるため- Modelで
ActiveRecord
を継承しているものが対象
応用編
- その他、いろんなパターンのトランザクションの使い方は、この記事がわかりやすかった
- 中でもなるほど〜って思ったのが、「複数のデータベースコネクションに分散されない」ということ
- 複数DBを取り扱ったことがなかったので知らなかった
- 複数DBを跨いでトランザクションをかける時には、
.transaction
をネストにしないといけないそう
おまけ
- ついでにコールバックも読んでみた
- コールバックも密接に関わってくるので、また今度まとめたい