重用aiosqlite连接

时间:2018-12-24 02:25:27

标签: python sqlite contextmanager

我只是不知道如何使用aiosqlite模块,以便保持连接以备后用。

基于aiosqlite project page

的示例
async with aiosqlite.connect('file.db') as conn:
    cursor = await conn.execute("SELECT 42;")
    rows = await cursor.fetchall()
    print('rows %s' % rows)

工作正常,但我想保持连接状态,以便可以在整个程序中使用它。

通常,使用sqlite,我打开一个连接,松开它,然后在程序的整个生命周期中使用它。

我也尝试过类似的事情:

conn = aiosqlite.connect('file.db')
c = await conn.__enter__()
AttributeError: 'Connection' object has no attribute '__enter__'

有没有上下文管理器可以使用此模块的方法吗?

1 个答案:

答案 0 :(得分:1)

“最佳”方法是让应用程序的入口点使用上下文管理器方法创建aiosqlite连接,将对连接对象的引用存储在某个地方,然后从内部运行应用程序的“运行循环”方法那个背景。这将确保在您的应用程序退出时,适当清理sqlite连接。看起来可能像这样:

async def main():
    async with aiosqlite.connect(...) as conn:
        # save conn somewhere
        await run_loop()

或者,您可以等待适当的进入/退出方法:

try:
    conn = aiosqlite.connect(...)
    await conn.__aenter__()
    # do stuff
finally:
    await conn.__aexit__()

无论如何,请注意aiosqlite的异步特性的确意味着共享连接可能会导致事务重叠。如果您需要确保并发查询是通过单独的事务进行的,那么每个事务将需要一个单独的连接。

根据Python sqlite docs关于共享连接的说明:

  

当使用具有相同连接的多个线程时,用户应序列化写入操作,以避免数据损坏。

这同样适用于aiosqlite和asyncio。例如,以下代码可能会将两个插入都重叠在一个事务中:

async def one(db):
    await db.execute("insert ...")
    await db.commit()

async def two(db):
    await db.execute("insert ...")
    await db.commit()

async def main():
    async with aiosqlite.connect(...) as db:
        await asyncio.gather(one(db), two(db))

正确的解决方案是为每个事务创建连接,或使用类似executescript的方式一次执行整个事务。