目次
FastAPI SQLAlchemy async – 非同期データベース接続を実装する
同期 DB と非同期 DB の違い
FastAPI は「非同期フレームワーク」ですが、多くの初心者が DB アクセスで同期コードを使ってしまい、非同期のメリットを活かせていません。
今回は、FastAPI と SQLAlchemy async を組み合わせて、「真の非同期 DB アクセス」を実装する方法についてまとめておきたいと思います。
もしご自身で先に公式ドキュメントをご覧になられる方は下のリンクから眺めてみてください。
Async I/O – SQLAlchemy ー 公式ドキュメント(英語)
対象となる方
- FastAPI を使っている方
- DB アクセスの性能を改善したい方
- 非同期プログラミングを深く学びたい方
※ このドキュメントは FastAPI 0.100 以上、SQLAlchemy 2.0 以上で書いていきます。
同期 DB vs 非同期 DB の比較
同期コード(ブロッキング)
from sqlalchemy import create_engine
engine = create_engine("postgresql://user:pass@localhost/db")
@app.get("/api/users")
async def get_users():
with Session(engine) as session:
# ← この行でブロック
# DB からのレスポンスを待つまで、他のリクエストは処理できない
users = session.query(User).all()
return {"users": users}非同期コード(ノンブロッキング)
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
@app.get("/api/users")
async def get_users(db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User))
# ← await で「一時停止」、他のリクエストを処理
users = result.scalars().all()
return {"users": users}SQLAlchemy async のセットアップ
SQLAlchemy async を使うには、以下をインストールします。
pip install sqlalchemy asyncpgその後、DB 接続を設定します。
from sqlalchemy.ext.asyncio import (
create_async_engine,
async_sessionmaker,
AsyncSession,
)
from sqlalchemy.pool import NullPool
engine = create_async_engine(
"postgresql+asyncpg://user:pass@localhost/db",
echo=False,
poolclass=NullPool,
)
async_session_maker = async_sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False,
)
async def get_db() -> AsyncSession:
async with async_session_maker() as session:
yield session実装例:CRUD 操作を非同期で
では、ユーザー CRUD の例を見てみましょう。
from fastapi import FastAPI, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from database import get_db
from models import User
from pydantic import BaseModel
app = FastAPI()
class UserCreate(BaseModel):
email: str
name: str
@app.get("/api/users")
async def list_users(db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User))
users = result.scalars().all()
return {"users": users}
@app.post("/api/users")
async def create_user(
user_data: UserCreate,
db: AsyncSession = Depends(get_db)
):
new_user = User(email=user_data.email, name=user_data.name)
db.add(new_user)
await db.commit()
await db.refresh(new_user)
return {"id": new_user.id, "email": new_user.email}Lambda 環境でのベストプラクティス
Lambda で FastAPI を動かす場合、DB 接続管理に注意が必要です。
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.pool import NullPool
engine = create_async_engine(
"postgresql+asyncpg://...",
poolclass=NullPool, # Lambda 向けの設定
connect_args={
"prepared_statement_name_func": lambda: f"__stmt_{uuid4()}__",
"statement_cache_size": 0,
},
)
# NullPool を使う理由:
# - Lambda のコンテナは一時的で、再利用時に DB 接続が閉じられている
# - コネクションプールを持つと、スタレな接続を握り続ける
# - NullPool で毎回新しい接続を作り直すのが安全パフォーマンス比較
100 個のリクエスト(各 100ms の DB 待機)を処理する場合:
| 方式 | 処理時間 | 説明 |
| 同期コード | 10 秒 | 100ms × 100 = 10 秒(順処理) |
| 非同期コード | 100ms | 100 個が並行処理 |
非同期で約 100 倍の性能向上が期待できます。
まとめ
以上で FastAPI + SQLAlchemy async について説明を終えたいと思います。
FastAPI の真のポテンシャルは「非同期 DB アクセス」と組み合わせることで初めて発揮されます。同期コードでは、せっかくの非同期フレームワークが活かしきれません。
全エンドポイントで await db.execute() を使う習慣をつけることで、スケーラブルで高性能な Web API が実現できますね ^^v いいね!非同期 DB!
ということで、ではまた〜

