トランザクションとは
トランザクションとは...コンピュータ システムにおける、永続的なデータに対する不可分な一連の処理
ロールバックとは...データ更新などで障害が起こったときに、その前の状態にまで戻ることをいう
トランザクションの具体例
例えばTwitterでフォローしてる人のツイートを通知ONにしている時、
・ツイートの作成
・通知の作成
の二つはセットで作成されるべきです。ツイートだけ作成に成功する、または通知だけ作成に成功するというのはよろしくないですね。そういう時に、処理をトランザクションとして書くことで一連の処理を確実にすることができるようになります。もし、エラーが発生した場合はロールバックされ元の何も手を加えられていない状態に戻ります。
個人開発やポートフォリオの作成ですとこういった守りの開発(他にもエラーハンドリングとか)が疎かになりがちかと思いますが実務では必須なので日頃の開発から癖づけておくと良いかもです。
Railsですとトランザクションはこんな感じに書けます。
def create
ActiveRecord::Base.transaction do
tweet = Tweet.create!(text: 'hoge')
@notification_targets.each do |target|
tweet.notifications.create!(target_id: target.id)
end
end
end
トランザクションするときは例外が出るようにしよう
ロールバックはトランザクション中に例外が発生することで起こります。なので逆にいうと作成してはいけない時にちゃんと例外を出さないと不正にレコードが作成されてしまいます。
具体的にいうと以下のようなコードが悪い例です。
def create
ActiveRecord::Base.transaction do
tweet = Tweet.new(text: 'hoge')
tweet.save
@notification_targets.each do |target|
notification = tweet.notifications.new(target_id: target.id)
notification.save
end
end
end
saveメソッドレコードの作成に失敗してもfalseを出すのみで例外は出ません。基本, エクスクラメーションマーク(!)をつけることで作成に失敗した際例外が出るようになるので"!"をつけましょう。
そして、トランザクション失敗時の処理はrescue部分に書くのですがrescueするエラーはちゃんと指定しましょう。なんでもrescueしてしまうのは良くないので。
def create
ActiveRecord::Base.transaction do
tweet = Tweet.new(text: 'hoge')
tweet.save
@notification_targets.each do |target|
notification = tweet.notifications.new(target_id: target.id)
notification.save
end
end
rescue ActiveRecord::RecordInvalid => invalid
puts invalid.record.errors
end