如何正确使用 asyncpg.connect 建立可执行 SQL 的数据库连接

`asyncpg.connect()` 返回的是一个协程对象,必须用 `await` 等待其完成才能获得真正的 `connection` 实例;否则直接调用 `.execute()` 会报错“coroutine object has no attribute 'execute'”。

在使用 asyncpg 进行异步 PostgreSQL 操作时,一个常见误区是混淆了协程函数调用实际连接对象。你代码中的核心问题在于:

conn = asyncpg.connect(...)  # ❌ 错误:这只是创建了一个协程对象,未执行!

这行代码并未真正建立数据库连接,而只是返回了一个 coroutine 对象。后续若尝试 conn.execute(...),Python 会提示:

AttributeError: 'coroutine' object has no attribute 'execute'

✅ 正确做法是显式 await 该协程,获取真正的 asyncpg.Connection 实例:

conn = await asyncpg.connect("postgresql://postgres@localhost/user")

此外,你的路由处理逻辑还存在多个关键问题,需一并修正:

✅ 完整修复示例(含最佳实践)

import asyncpg
from aiogram import Router
from aiogram.types import Message
from data.config import Config

Data_base = Router()


# ✅ 推荐:封装连接为工具函数,并确保正确 await
async def get_db_connection():
    return await asyncpg.connect("postgresql://postgres@localhost/user")


@Data_base.message()
async def including_data_from_user(message: Message):
    try:
        # ✅ 正确获取连接(await 协程)
        conn = await get_db_connection()

        # ✅ 使用 $1, $2 等占位符防止 SQL 注入(强烈推荐!)
        await conn.execute(
            """
            INSERT INTO "user" (first_name, last_name, age, telegram_id)
            VALUES ($1, $2, $3, $4)
            """,
            message.from_user.first_name,
            message.from_user.last_name,
            1,
            message.from_user.id
        )
        await message.answer("✅ 用户数据已成功写入数据库!")

    except Exception as e:
        await message.answer(f"❌ 数据库操作失败:{e}")
    finally:
        # ✅ 务必关闭连接(或使用连接池更佳)
        if 'conn' in locals() and conn:
            await conn.close()

⚠️ 关键注意事项

  • 永远不要拼接 SQL 字符串:你原代码中 f'''INSERT ... {message.from_user.first_name}''' 极易导致 SQL 注入。务必使用 $1, $2 占位符 + 参数化查询。
  • 表名 user 是 PostgreSQL 保留关键字:建议用双引号包裹 "user",或重命名表(如 users)。
  • 避免重复创建连接:高频场景应使用 asyncpg.create_pool() 创建连接池,而非每次 connect()。
  • 资源清理不可少:conn.close() 应放在 finally 块中,或使用 async with conn.transaction(): 上下文管理。

遵循以上修正,即可彻底解决 'coroutine' object has no attribute 'execute' 错误,并构建健壮、安全的异步数据库交互逻辑。