1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【初心者向け】SQLAlchemyの仕組みを理解する|Core・ORM・Sessionの基本概念

1
Posted at

はじめに

「SQLAlchemyを使いたいけど、EngineとかSessionとか、何がなんだかわからない…」

そんな悩みを持っている方も多いのではないでしょうか。SQLAlchemyはPythonで最も人気のあるORMライブラリですが、独自の概念が多く、最初はとっつきにくく感じるかもしれません。

この記事では、SQLAlchemyの仕組みと構造を中心に解説します。「なぜそう動くのか」を理解することで、実際のコードを書くときにも迷わなくなりますよ。

対象読者

  • Pythonの基礎知識がある方
  • SQLAlchemyをこれから学びたい方
  • 「とりあえず動くコード」ではなく、仕組みを理解したい方

前提知識

  • Pythonの基本文法(クラス、関数など)
  • データベースの基礎概念(テーブル、レコード、SQLとは何か程度)

SQLAlchemyとは?

SQLAlchemyは、Pythonでデータベースを操作するためのライブラリです。2006年から開発が続いており、Pythonエコシステムにおいて最も成熟したORMの一つとして知られています。

主な特徴

特徴 説明
ORM機能 PythonオブジェクトとDBテーブルを対応付け
Pythonic 生のSQLではなくPythonコードでDB操作
DB非依存 MySQL、PostgreSQL、SQLite等を同じコードで操作可能
柔軟性 低レベル(SQL直書き)から高レベル(ORM)まで対応

なぜSQLAlchemyを使うのか?

生のSQLを直接書くこともできますが、SQLAlchemyを使うことで以下のメリットがあります。

生のSQLの場合
# データベースごとに微妙に文法が違う
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))  # MySQL
cursor.execute("SELECT * FROM users WHERE id = $1", (user_id,))  # PostgreSQL
SQLAlchemyの場合
# どのデータベースでも同じコード
result = session.execute(select(User).where(User.id == user_id))

データベースを変更しても、コードの書き換えが最小限で済むのは大きなメリットですね。

SQLAlchemyの2層構造:CoreとORM

SQLAlchemyを理解する上で最も重要なのが、CoreとORMの2層構造です。これを理解すれば、SQLAlchemyの全体像が見えてきます。

SQLAlchemy Coreとは

Coreは、SQLAlchemyの基盤となる低レベルAPIです。

主な役割:

  • データベース接続の管理(Engine)
  • SQLステートメントの構築(select, insert, update, delete)
  • トランザクション管理

Coreは「SQLをPythonで表現するためのツールキット」と考えるとわかりやすいでしょう。

Coreを使った例
from sqlalchemy import create_engine, text

engine = create_engine("sqlite:///example.db")

with engine.connect() as conn:
    result = conn.execute(text("SELECT * FROM users"))
    for row in result:
        print(row)

SQLAlchemy ORMとは

ORM(Object Relational Mapper)は、Coreの上に構築された高レベルAPIです。

主な役割:

  • PythonクラスとDBテーブルのマッピング
  • オブジェクトの永続化(保存・更新・削除)
  • リレーションシップの管理(1対多、多対多など)

ORMを使うと、データベースのレコードをPythonオブジェクトとして扱えます。

ORMを使った例
# Userクラスがusersテーブルに対応
user = User(name="田中太郎", email="tanaka@example.com")
session.add(user)
session.commit()

# オブジェクトとして操作できる
print(user.name)  # "田中太郎"

CoreとORMの使い分け

ユースケース 推奨
Webアプリケーション開発 ORM
データ分析・バッチ処理 Core または 両方
複雑なJOINや集計クエリ Core
単純なCRUD操作 ORM

SQLAlchemy 2.0では、ORMでもCoreスタイルのselect()構文が使えるようになり、両者の統合が進んでいます。どちらか一方に縛られる必要はありません。

主要コンポーネントの役割

SQLAlchemyには、いくつかの重要なコンポーネントがあります。それぞれの役割を見ていきましょう。

Engine(エンジン)

Engineは、データベースへの接続の「入り口」となるオブジェクトです。

Engineの作成
from sqlalchemy import create_engine

# 接続文字列でデータベースを指定
engine = create_engine("postgresql://user:password@localhost/mydb")

コネクションプーリング

Engineの重要な機能の一つがコネクションプーリングです。

コネクションプーリングとは?

データベース接続の作成は重い処理です。毎回接続を作り直すのではなく、接続を「プール」(貯めておく場所)で管理し、再利用することでパフォーマンスを向上させます。Engineはこれを自動で行ってくれます。

Engineは「接続」ではない

よくある誤解ですが、Engineは接続そのものではありません。Engineは接続を管理するファクトリであり、メソッド実行時に随時コネクションの取得・解放を行います。

# Engineは1つだけ作成(アプリ起動時)
engine = create_engine("sqlite:///example.db")

# 実際の接続はメソッド呼び出し時に取得される
with engine.connect() as connection:
    # ここで初めて接続が使われる
    result = connection.execute(text("SELECT 1"))
# ここで接続がプールに返却される

Session(セッション)

Sessionは、ORMを使う際の「作業領域」です。オブジェクトの変更を追跡し、データベースとの同期を管理します。

Sessionの基本的な使い方
from sqlalchemy.orm import sessionmaker

# Sessionファクトリを作成
Session = sessionmaker(bind=engine)

# Sessionインスタンスを作成
with Session() as session:
    user = session.get(User, 1)
    user.name = "新しい名前"
    session.commit()

Unit of Workパターン

SessionはUnit of Work(作業単位)パターンを実装しています。

  • セッション内での変更はメモリ上で追跡される
  • commit()を呼ぶまでデータベースには反映されない
  • エラー時はrollback()で全ての変更を取り消せる

Identity Map(同一性マップ)

SessionにはIdentity Mapという仕組みがあります。これは、同じ主キーを持つレコードに対して、常に同じPythonオブジェクトを返す機能です。

# 同じIDで2回取得しても、同じオブジェクトが返される
user1 = session.get(User, 1)
user2 = session.get(User, 1)

print(user1 is user2)  # True(同一オブジェクト)

これにより、同じセッション内でデータの不整合が起きることを防げます。

Model(モデル)

Modelは、データベースのテーブルをPythonクラスとして表現したものです。

SQLAlchemy 2.0の書き方

SQLAlchemy 2.0では、型アノテーションを活用した新しい書き方が推奨されています。

models.py
from sqlalchemy import String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

# ベースクラスの定義
class Base(DeclarativeBase):
    pass

# モデルの定義
class User(Base):
    __tablename__ = "users"
    
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(100))
    email: Mapped[str] = mapped_column(String(255), unique=True)
    is_active: Mapped[bool] = mapped_column(default=True)
要素 説明
DeclarativeBase 全モデルの基底クラス
__tablename__ 対応するテーブル名
Mapped[型] カラムの型を明示
mapped_column() カラムの定義

従来のdeclarative_base()やColumn()も使えますが、SQLAlchemy 2.0では上記の書き方が推奨されています。新規プロジェクトでは新しい書き方を使いましょう。

データの流れを図解で理解する

ここまで学んだコンポーネントが、実際にどう連携するのか見てみましょう。

実際のデータ操作の流れ

データ取得(SELECT)の例:

# 1. Sessionを通じてクエリを実行
with Session() as session:
    # 2. select文を構築
    stmt = select(User).where(User.id == 1)
    
    # 3. Session経由でEngineがDBに問い合わせ
    user = session.execute(stmt).scalar_one()
    
    # 4. 結果がPythonオブジェクトとして返される
    print(user.name)

データ作成(INSERT)の例:

with Session() as session:
    # 1. モデルのインスタンスを作成
    new_user = User(name="山田花子", email="yamada@example.com")
    
    # 2. Sessionに追加(まだDBには保存されない)
    session.add(new_user)
    
    # 3. commit()でDBに反映
    session.commit()
    
    # 4. 自動採番されたIDも取得できる
    print(new_user.id)

SQLAlchemy 1.x vs 2.0:何が変わった?

SQLAlchemy 2.0は2023年にリリースされた大きなアップデートです。主な変更点を押さえておきましょう。

クエリの書き方

1.x系(レガシー):

# session.query()を使う書き方(非推奨)
users = session.query(User).filter(User.is_active == True).all()

2.0系(推奨):

# select()を使う書き方(推奨)
from sqlalchemy import select

stmt = select(User).where(User.is_active == True)
users = session.execute(stmt).scalars().all()

モデルの定義

1.x系:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String

Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    name = Column(String(100))

2.0系:

from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import String

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(100))

主な改善点

項目 説明
一貫性 CoreとORMでクエリ構文が統一
型安全性 型アノテーションによるIDEサポート向上
明示性 何が起きているか分かりやすい設計
パフォーマンス 内部処理の最適化

新規プロジェクトでは必ずSQLAlchemy 2.0の書き方を使いましょう。1.x系の書き方はレガシーとされており、将来的に非推奨となる可能性があります。

まとめ

この記事では、SQLAlchemyの基本的な仕組みと概念を解説しました。

要点の振り返り

  1. 2層構造

    • Core:低レベルAPI、SQL構築と接続管理
    • ORM:高レベルAPI、オブジェクトとテーブルのマッピング
  2. 主要コンポーネント

    • Engine:接続の入り口、コネクションプーリング
    • Session:作業単位、変更の追跡と永続化
    • Model:テーブルをPythonクラスで表現
  3. SQLAlchemy 2.0

    • select()による統一されたクエリ構文
    • 型アノテーションを活用した新しいモデル定義

参考リンク

1
5
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
1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?