はじめに
先日、「トランザクション」という言葉を知り、実際にWebアプリケーションを作ろうとすると避けて通れない重要な仕組みだということがわかりました。
トランザクションとは?
トランザクションとは複数のデータベース操作をひとまとめにした処理の単位のこと
IT分野でのトランザクション
Ruby on Railsのようなアプリケーション開発では、データベースに対する一連の操作をひとかたまりにしたものを指すことがわかりました。私が学んだActiveRecordでも、この概念が使われているんですね。
ビジネス分野でのトランザクション
一方、ビジネスの世界では「商取引」という意味で使われるそうです。例えば、商品の「購入」と「支払い」という2つの行為がセットになったものがトランザクションということです。
Railsにおけるトランザクション処理
一連の操作をまとめて処理する
Railsでトランザクション処理を行うと、複数のデータベース操作を1つの単位として管理できるということを学びました。
調べた例として、銀行の振込処理がよく使われていました
- A口座(残高50,000円)から20,000円をB口座(残高20,000円)に振り込む場合
この処理には以下の2つのステップが必要
- A口座から20,000円を引き出し → 残高30,000円
- B口座に20,000円を追加 → 残高40,000円
もし、1つ目の処理は成功したけれど、2つ目の処理でエラーが発生したらどうなってしまうのか。
A口座の20,000円だけが消えてしまい、大変なことになる。
トランザクション処理を使うことで、このような問題を防げるようです。すべての処理が成功した場合のみ変更を確定し、どれか1つでも失敗した場合は、すべての変更を取り消してくれる。
処理の完了を保証する
勉強してわかったのは、トランザクション処理の結果は**「成功」か「失敗」の2つだけ**ということです。とてもシンプルです。
これによりデータの整合性を保つことができるのですが、一方で大量のトランザクションが同時に発生すると、システムの負荷が高くなるというデメリットもあることを知りました。
ACID特性について
色々調べていると、トランザクション処理には4つの重要な特性があることがわかりました。それぞれの頭文字をとってACID特性と呼ばれるそうです。
原子性(Atomicity)
すべて実行するか、まったく実行しないか
トランザクション内のすべての操作が完了するか、エラーが発生した場合はすべての処理が取り消されます。「半分だけ実行される」ということはないんですね。
一貫性(Consistency)
実行前後でデータの整合性が保たれる
データベースに矛盾が生じないよう、一定のルールに基づいて処理が行われます。例えば、「残高は負の数にならない」というルールがあれば、それに反する処理はエラーになるということです。
独立性(Isolation)
他のトランザクションの影響を受けない
複数のトランザクションが同時に実行されても、それぞれが独立して動作し、お互いに干渉しないということを学びました。
永続性(Durability)
処理結果が永続的に保存される
トランザクションが成功した場合、その結果は必ずデータベースに保存され、システム障害が発生しても失われないようです。
例
基本的なトランザクション処理
# トランザクションを開始
ActiveRecord::Base.transaction do
# 商品の在庫を減らす
product = Product.find(123)
product.update!(stock_quantity: product.stock_quantity - 10)
# 処理が成功した場合、自動的にコミットされる
end
エラーハンドリングを含む例
begin
ActiveRecord::Base.transaction do
# 注文データを作成
order = Order.create!(order_id: 1, customer_id: 101, order_date: Date.current)
# 注文商品データを作成
OrderItem.create!(order_id: 1, product_id: 'A123', quantity: 5)
# ここまでですべて成功した場合、自動的にコミット
end
rescue => e
# エラーが発生した場合、自動的にロールバック
puts "エラーが発生しました: #{e.message}"
end
コミット(COMMIT)
処理が正常に完了し、変更をデータベースに確定すること。Railsでは、トランザクションブロックが正常に終了すると自動的にコミットされることがわかりました。
ロールバック(ROLLBACK)
エラーが発生した際に、変更を取り消して元の状態に戻すこと。Railsでは、例外が発生すると自動的にロールバックされるんですね。
並行制御
複数のトランザクションが同時に実行される際に、データの整合性を保つための制御方法だそうです。
デッドロック
複数のトランザクションがお互いの処理を待ち合って、進行しなくなる状態のことです。実際に遭遇したことはまだありませんが、知っておいた方が良さそうです。
よく使われる場面
実際にアプリを作ってみて、どんな場面でトランザクションが使われるのかを知りました。
ECサイトの注文処理
- 商品の在庫減少
- 注文データの作成
- 決済処理
これらすべてが成功した場合のみ、注文を確定するんですね。
ユーザー登録処理
- ユーザーアカウントの作成
- プロフィール情報の登録
- 初期設定の適用
データの一括更新
複数のレコードを同時に更新する際に、一部だけ更新されてデータに不整合が生じることを防ぐために使います。
まとめ
- トランザクション:複数のデータベース操作をひとまとめにした処理単位
- ACID特性:原子性、一貫性、独立性、永続性の4つの特性
-
Railsでの実装:
ActiveRecord::Base.transaction
ブロックを使用 - 重要性:データの整合性を保ち、安全なアプリケーションを作るために必須
Railsアプリケーション開発において、トランザクション処理は私たちが作るサービスの信頼性を大きく左右する重要な概念だということがわかりました。
初学者のため、間違えていたらすいません。