← 中文资源

简体中文版本

SQLAlchemy 异步会话连接池

用 SQLAlchemy 异步引擎管理连接池:会话按请求作用域创建、事务上下文自动提交回滚、gather 并发下连接必然归还。

阅读英文原文

示例说明

异步 ORM 的资源纪律比同步更苛刻:连接不归还会迅速耗尽池子拖垮全部请求。async with SessionFactory 的会话上下文保证 close 必然执行——连接回池;session.begin 的事务上下文把提交回滚原子化,异常即回滚。两个转账并发执行验证池在竞争下的正确调度。

技术要点

  • 会话上下文确保连接必归池
  • begin 上下文自动提交回滚
  • pool_recycle 防长连接被服务端掐断

代码解读

引擎配置十常驻加二十溢出的池参数与五秒获取超时;1800 秒回收周期匹配数据库的空闲超时防借用死连接。transfer 的两个更新语句在同一 begin 里成为原子单元;main 的 gather 并发跑两笔反向转账后汇总余额验证净效应。dispose 收尾关闭全部池连接。

使用建议

会话中禁止跨 await 持有未提交事务过久。池大小按数据库总预算与实例数折算。溢出连接是短时弹性,不该成为常态。

代码示例

import asyncio

from sqlalchemy import text
from sqlalchemy.ext.asyncio import (
    async_sessionmaker,
    create_async_engine,
)

engine = create_async_engine(
    'postgresql+asyncpg://user:pass@localhost/app',
    pool_size=10,
    max_overflow=20,
    pool_timeout=5,
    pool_recycle=1800,
    echo=False,
)

SessionFactory = async_sessionmaker(engine, expire_on_commit=False)


async def transfer(from_id: int, to_id: int, amount: int) -> None:
    async with SessionFactory() as session:
        async with session.begin():
            await session.execute(
                text('UPDATE accounts SET balance = balance - :a WHERE id = :i'),
                {'a': amount, 'i': from_id},
            )
            await session.execute(
                text('UPDATE accounts SET balance = balance + :a WHERE id = :i'),
                {'a': amount, 'i': to_id},
            )


async def report_total() -> int:
    async with SessionFactory() as session:
        result = await session.execute(text('SELECT sum(balance) FROM accounts'))
        return result.scalar_one()


async def main() -> None:
    await asyncio.gather(
        transfer(1, 2, 50),
        transfer(2, 1, 20),
    )
    print('net effect applied:', await report_total())
    await engine.dispose()


asyncio.run(main())