1. Core Concept#
Synchronous SQLAlchemy (classic):
Operations block the Python thread until they complete.
Typical usage:
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
Base = declarative_base()
engine = create_engine("sqlite:///test.db")
Session = sessionmaker(bind=engine)
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String)
# Sync usage
with Session() as session:
user = session.query(User).filter_by(name="Alice").first()
print(user.id)
Asynchronous SQLAlchemy (asyncio):
Uses
async/await, so your code doesn’t block the event loop while waiting for the database.Requires an async-compatible database driver, like
asyncpgfor PostgreSQL oraiosqlitefor SQLite.Typical usage:
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker, declarative_base
import asyncio
Base = declarative_base()
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async def get_user():
async with AsyncSessionLocal() as session:
result = await session.execute(
"SELECT * FROM users WHERE name=:name", {"name": "Alice"}
)
user = result.fetchone()
print(user)
asyncio.run(get_user())
2. Key Differences#
Aspect |
Synchronous |
Asynchronous |
|---|---|---|
Execution |
Blocks thread until query finishes |
Non-blocking, allows other coroutines to run while waiting |
Driver |
Standard DB drivers (psycopg2, pymysql, sqlite3) |
Async drivers (asyncpg, aiosqlite, aiomysql) |
Session |
|
|
Query Execution |
Direct function calls: |
|
Engine |
|
|
Transactions |
|
|
Performance |
Good for single-threaded or blocking apps |
Better for high-concurrency async apps (web servers, async tasks) |
ORM Support |
Full ORM |
Full ORM, but you must |
3. Important Notes#
Async is not faster for a single query: It mainly helps if your app is doing many concurrent DB operations, like a web server handling hundreds of requests simultaneously.
Mixing sync and async sessions is tricky: You should generally stick to one pattern in a given context.
Some SQLAlchemy features are slightly different in async mode:
session.execute()returns aResultobject; you usually use.fetchone(),.fetchall(), or.scalars().Lazy loading of relationships is async too (
await user.addresses).