🐢
Rails + PostgreSQL でトランザクションを書くときに、トランザクションの外で行ったデータ操作の影響
これは何?
- Rails + PostgreSQLでトランザクションを書くとき、トランザクションの内外でデータ操作の影響がどう変わるかの備忘録
- 環境
Rails 8
PostgreSQL 17
トランザクションの中でのデータ変更について
トランザクションの中で発生したupdate, create, destroy
などのデータ変更は、分離レベルに関係なく、コミットされるまでトランザクションの外には反映されません。
トランザクションの外でのデータ変更について
オプションなしのトランザクションの場合
ActiveRecord::Base.transaction
をisolation
オプション指定なしで実行すると、分離レベルは PostgreSQL
ではデフォルトのRead Commitedとなります。この状態だと、トランザクションの外でcommitされたデータがトランザクション内に反映されます。
たとえば以下のトランザクションでbinding.b
した箇所で、別のモデルをcreate,update,destroy
してコミットすると、コミット結果をトランザクション内で見ることができます。
def test_transaction
Supplier.transaction do
binding.b
update!(name: "updated_name")
end
end
PostgreSQLのデフォルトより高レベルの分離オプションを指定したトランザクションの場合
ActiveRecord::Base.transaction
を、PostgreSQL
のデフォルトより高レベルのisolation
オプション指定あり(:repeatable_read or :serializable
)で実行すると、トランザクションの外でcommitされたデータはトランザクション内に反映されません。上記のトランザクションを以下のように変えると、別のモデルのデータはトランザクション開始時点のデータを参照します。
def test_transaction
- Supplier.transaction do
+ Supplier.transaction(isolation: :repeatable_read) do
binding.b
update!(name: "updated_name")
end
end
使い分けのユースケース
意図しないロールバックが発生したときに適切にrescue
せず、500
エラーがユーザーに出てしまう場合は対策したほうがいいかも
参考
Discussion