0
0

はじめに

今回は課題を進めていくなか、改めて「?」とかんじたトランザクションと関係するロールバックについて学んだことをアウトプットしたいと思います。

トランザクションとは

  • 意味: 一連のデータベース操作を一つのまとまった処理単位として扱うこと
  • 特徴: トランザクション内で行われたすべての操作は、すべて成功するか、またはすべて失敗するかのどちらかになる。これをACID特性と呼ぶ
    Atomicity(原子性): 全ての操作が完全に実行されるか、全く実行されないかのどちらか。
    Consistency(一貫性): トランザクションが完了すると、データベースは常に一貫した状態になる。
    Isolation(独立性): 同時に実行されるトランザクションは互いに干渉しない。
    Durability(永続性): トランザクションが完了した後、その結果は永続的に保存される。

ロールバックとは

  • 意味: トランザクション内でエラーが発生した場合、トランザクション開始前の状態にデータベースを戻すこと
  • 機能: トランザクション内の全ての操作を無効にすることで、データの一貫性を保つ
  • 使用することで得られる利点
    データの一貫性の確保: 複数の操作が途中で失敗した場合でも、データベースが不整合な状態になるのを防げる
    エラーハンドリングの簡素化: エラーが発生した場合、ロールバックを行うだけでデータベースの状態を元に戻せる
    信頼性の向上: データベース操作が失敗しても、安全にリカバリできるため、アプリケーション全体の信頼性が向上する

具体例

銀行の送金システムで、以下の2つの操作をトランザクションとして扱うとする

  • 送金元の口座から指定金額を引き落とす
  • 送金先の口座に指定金額を入金する

もし2番目の操作でエラーが発生した場合、1番目の操作も無効にして元の状態に戻す(ロールバック)ことで、データの一貫性を保つことができる

def transfer_funds(from_account, to_account, amount)
  ActiveRecord::Base.transaction do
    from_account.decrement!(:balance, amount)
    to_account.increment!(:balance, amount)
  end
rescue => e
  Rails.logger.error("Transfer failed: #{e.message}")
  raise ActiveRecord::Rollback
end

このようにトランザクションとロールバックを使用することで、信頼性の高いデータベース操作が実現できる

詳細なシミュレートは次の通り

require 'sequel'

# データベース接続(SQLiteを例に使用)
DB = Sequel.sqlite

# テーブルの作成
DB.create_table :accounts do
  primary_key :id
  String :name
  Float :balance
end

# アカウントモデルの定義
class Account < Sequel::Model
end

# アカウントの初期データを追加
account_a = Account.create(name: 'Aさん', balance: 1000.0)
account_b = Account.create(name: 'Bさん', balance: 500.0)

def transfer(from_account, to_account, amount)
  DB.transaction do
    # Aさんの口座からお金を引き出す
    from_account.update(balance: from_account.balance - amount)
    raise "残高不足" if from_account.balance < 0

    # Bさんの口座にお金を入れる
    to_account.update(balance: to_account.balance + amount)
  end
rescue => e
  puts "エラー発生: #{e.message}"
  raise Sequel::Rollback
end

# 振り込み操作
begin
  transfer(account_a, account_b, 200.0)
  puts "振り込み成功"
rescue
  puts "振り込み失敗"
end

# 結果の確認
puts "Aさんの残高: #{account_a.reload.balance}"
puts "Bさんの残高: #{account_b.reload.balance}"

さいごに

ネットで何でも決済できるようになっていて、具体例のようなトランザクションとロールバックの仕組みの重要性を改めて実感しました。こういうところで活用されているとは…:open_mouth:
私もいつか世の中のためになるようなものをつくりたいです

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0