Лучший способ открыть / закрыть соединение с БД с помощью async/await
В обучающих программах, которые я обнаружил, всегда открываются и закрываются соединения для каждого запроса, например:
import asyncio
import asyncpg
async def run():
conn = await asyncpg.connect(user='user', password='password',
database='database', host='127.0.0.1')
values = await conn.fetch('''SELECT * FROM mytable''')
await conn.close()
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
Хотя это работает для одной функции, а как насчет веб-приложения?
IE: например, в Tornado каждый URL является классом, что приводит к множеству классов / методов.
У меня есть привычка открывать соединение блокирующим образом, а затем использовать оболочку для выполнения асинхронных вызовов БД и закрывать соединение только для того, чтобы грациозно завершить работу сервера, что является наилучшей практикой в этом случае async/await
?
1 ответ
Не используя asyncpg, я предполагаю, что, как и в большинстве пакетов, совместимых с asyncio, существует менеджер контекста async, позволяющий выполнять именно то, что вы запрашиваете.
Что-то вроде:
async with asyncpg.create_pool(**kwargs) as pool:
async with pool.acquire() as connection:
async with connection.transaction():
result = await connection.fetchval(fetch stuff)
connection.execute(insert stuff with result)
(как взято из этого вопроса)
Проверьте документы для упоминания контекстных менеджеров или примеров с async with
заявления или, если ничего другого, то проверьте классы в исходном коде, которые реализуют __aenter__
, __aexit__
методы.
Изменить 1:
Приведенный выше пример частично взят из вопроса, с которым я связан, и частично придуман для полноты. Но чтобы ответить на ваши комментарии о том, что делают операторы with:
async with asyncpg.create_pool(**kwargs) as pool:
#in this block pool is created and open
async with pool.acquire() as connection:
# in this block connection is acquired and open
async with connection.transaction():
# in this block each executed statement is in a transaction
execute_stuff_with_connection(connection)
# now we are back up one logical block so the transaction is closed
do_stuff_without_transaction_but_with_connection(connection)
# now we are up another block and the connection is closed and returned to the pool
do_more_stuff_with_pool(pool)
# now we are up another level and the pool is closed/exited/cleaned up
done_doing_async_stuff()
Я не уверен, насколько это хорошее объяснение, возможно, вам стоит ознакомиться с менеджерами контекста.