FastAPI絡みで非同期処理をやるためにDB操作も非同期処理が必要なので、SQLAlchemyを使った非同期処理を試してみる。
準備
非同期処理をするために、非同期に対応したドライバのインストールが必要。
psycogp2よりも3倍早いらしい、asyncpg
をインストールする。
pip install asyncpg
これをやる
SQLAlchemyのページにある非同期のサンプルを動かす。
エンジンの生成
非同期の場合、エンジンインスタンスを生成する際は、create_async_engine
を実行する。
また、ドライバはasyncpg
を使用する。
url = "postgresql+asyncpg://postgres:example@localhost:5432/postgres" engine = create_async_engine(url, echo=True)
コネクションを非同期コンテキストマネージャを使って実行
async with
を使用して、DBとのコネクションを生成する。実行もawait
を使用する。
async with engine.connect() as conn: result = await conn.execute(select(t1).where(t1.c.name == "some name 1")) print(result.fetchall())
非同期でのORM
func.now()が効かない??
SQLAlchemyに載っているORMのサンプルを写経してみたが、func.now()がうまく動いてないみたい?
下記のエラーが発生している。
File "asyncpg/protocol/protocol.pyx", line 207, in bind_execute asyncpg.exceptions.NotNullViolationError: null value in column "create_date" of relation "a" violates not-null constraint DETAIL: Failing row contains (9, a1, null).
from sqlalchemy import func
応急処置として、create_date
に現在時刻を設定するように変更したら、データを登録して検索もできた。
with async_session()
だけを実行して、SQLの発行をしている箇所とwith async_session()
の後にwith session.begin()
を実行している箇所がある。
これはwith句を抜けた後に、自動でコミット/ロールバックするかしないかの違いになる。
with session.begin()
は、トランザクションが開始されるので自動でコミット/ロールバックが実行される。
- beginあり
async with async_session() as session: async with session.begin():
- beginなし
async with async_session() as session: stmt = select(A).order_by(A.id).options(selectinload(A.bs)) result = await session.execute(stmt)
with句を2段で書かずに、以下のようにできる。
async with async_session.begin() as session:
最後に
SQLAlchemyでの非同期処理がなんとなく分かったので、次はFastAPI+SQLAlchemyをやってみたいと思う。