簡體   English   中英

在 Python Gino 中獲取池連接(異步)

[英]Acquiring pool connections in Python Gino (async)

我正在使用 Postgres、Python3.7 和asyncio + asyncpg + gino (ORM-ish) + aiohttp (路由,web 響應)。

我在我的數據庫testdb中創建了一個小的 postgres 表users並插入了一行:

testdb=# select * from users;
 id | nickname
----+----------
  1 | fantix

我正在嘗試設置我的數據庫,以便在請求進入時可以在路由中使用 ORM。

import time
import asyncio
import gino

DATABASE_URL = os.environ.get('DATABASE_URL')

db = gino.Gino()

class User(db.Model):
  __tablename__ = 'users'
  id = db.Column(db.Integer(), primary_key=True)
  nickname = db.Column(db.Unicode(), default='noname')

kwargs = dict(
  min_size=10,
  max_size=100,
  max_queries=1000,
  max_inactive_connection_lifetime=60 * 5,
  echo=True
)

async def test_engine_implicit():
  await db.set_bind(DATABASE_URL, **kwargs)
  return await User.query.gino.all()      # this works

async def test_engine_explicit():
  engine = await gino.create_engine(DATABASE_URL, **kwargs)
  db.bind = engine
  async with engine.acquire() as conn:
    return await conn.all(User.select())  # this doesn't work!

users = asyncio.get_event_loop().run_until_complete(test_engine_implicit())
print(f'implicit query: {users}')

users = asyncio.get_event_loop().run_until_complete(test_engine_explicit())
print(f'explicit query: {users}')

output 是:

web_1    | INFO gino.engine._SAEngine SELECT users.id, users.nickname FROM users
web_1    | INFO gino.engine._SAEngine ()
web_1    | implicit query: [<db.User object at 0x7fc57be42410>]
web_1    | INFO gino.engine._SAEngine SELECT
web_1    | INFO gino.engine._SAEngine ()
web_1    | explicit query: [()]

這很奇怪。 “顯式”代碼本質上是針對數據庫運行一個裸露的SELECT ,這是沒有用的。

我在文檔中找不到兩種方法:1)使用 ORM,2)明確檢查池中的連接。

我的問題:

  1. await User.query.gino.all()是否從池中簽出連接? 它是如何發布的?
  2. 我將如何在事務中包裝查詢? 我很不安,因為我無法明確控制何時/何地從池中獲取連接,以及如何釋放它。

我本質上希望test_engine_explicit()中的明確風格與 Gino 一起工作,但也許我只是不明白 Gino ORM 是如何工作的。

我以前從未使用過 GINO,但在快速查看代碼后:

  1. GINO 連接只是按原樣執行提供的子句 因此,如果您提供裸露User.select() ,那么它不會增加任何內容。
  2. 如果您想實現與使用User.query.gino.all()相同的效果,但要自己維護連接,那么您可以按照文檔並使用User.query而不是普通的User.select()
async with engine.acquire() as conn:
    return await conn.all(User.query) 

剛剛測試過,對我來說效果很好。

關於連接池,我不確定我的問題是否正確,但Engine.acquire 默認創建一個可重用連接,然后將其添加到池中,實際上是一個堆棧:

 :param reusable: Mark this connection as reusable or otherwise. This has no effect if it is a reusing connection. All reusable connections are placed in a stack, any reusing acquire operation will always reuse the top (latest) reusable connection. One reusable connection may be reused by several reusing connections - they all share one same underlying connection. Acquiring a connection with ``reusable=False`` and ``reusing=False`` makes it a cleanly isolated connection which is only referenced once here.

GINO 中還有一個手動事務控制,例如,您可以創建一個不可重用、不可重用的連接並手動控制事務流:

async with engine.acquire(reuse=False, reusable=False) as conn: 
     tx = await conn.transaction() 
     try: 
          await conn.status("INSERT INTO users(nickname) VALUES('e')") 
          await tx.commit() 
     except Exception: 
          await tx.rollback() 
          raise

至於連接釋放,我找不到任何證據表明GINO自己釋放連接。 我猜這個池是由 SQLAlchemy 核心維護的。

我肯定沒有直接回答你的問題,但希望它能以某種方式幫助你。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM