Получение подключений к пулу в Python Gino (асинхронно) - PullRequest
1 голос
/ 30 октября 2019

Я использую Postgres, Python3.7 с asyncio + asyncpg + gino (ORM-ish) + aiohttp (маршрутизация, веб-ответы).

Я создал небольшойpostgres таблицу users в моей базе данных testdb и вставил одну строку:

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}')

Вывод:

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.

1 Ответ

0 голосов
/ 30 октября 2019

Я никогда раньше не использовал 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.

Я определенно не ответил на ваши вопросы напрямую, но надеюсь, что это вам как-то поможет.

...