python - SQLAlchemy - 使用与数据库和 session 的连接(不明确的行为和文档中的部分)

标签 python postgresql sqlalchemy

我使用 SQLAlchemy(非常好的 ORM,但文档不够清晰)与 PostgreSQL 通信
一切都很好,直到达到最大连接限制的 postgres“崩溃”原因为止:不允许更多连接 (max_client_conn)
那件事让我觉得我做错了。经过几次实验后,我想出了如何不再面对这个问题,但还有一些问题

下面您将看到代码示例(在 Python 3+ 中,PostgreSQL 设置是默认设置)没有和有提到的问题,我最终想听到的是以下问题的答案:

  1. 上下文管理器究竟对连接和 session 做了什么?关闭 session 并处理连接还是什么?
  2. 为什么代码的第一个工作示例在没有 NullPool 作为“connect”方法中的 poolclass 的情况下表现得像有问题的示例?
  3. 为什么在第一个示例中我只为所有查询获得一个到数据库的连接,而在第二个示例中我为每个查询获得单独的连接? (如果我理解错了,请纠正我,正在用“pgbouncer”检查)
  4. 当您将 SQLAlchemy 和 PostgreSQL DB 用于多个脚本实例(或脚本中的单独线程)时,打开和关闭连接(和/或使用 Session)的最佳做法是什么?他们每个人? (我的意思是原始 SQLAlchemy 不是 Flask-SQLAlchemy 或像这样的东西)

    没有问题的代码工作示例:

连接到数据库:

from sqlalchemy.pool import NullPool  # does not work without NullPool, why?

def connect(user, password, db, host='localhost', port=5432):
    """Returns a connection and a metadata object"""
    url = 'postgresql://{}:{}@{}:{}/{}'.format(user, password, host, port, db)

    temp_con = sqlalchemy.create_engine(url, client_encoding='utf8', poolclass=NullPool)
    temp_meta = sqlalchemy.MetaData(bind=temp_con, reflect=True)

    return temp_con, temp_meta

使 session 与 DB 一起工作的函数:

from contextlib import contextmanager

@contextmanager
def session_scope():
    con_loc, meta_loc = connect(db_user, db_pass, db_instance, 'localhost')
    Session = sessionmaker(bind=con_loc)

    """Provide a transactional scope around a series of operations."""
    session = Session()
    try:
        yield session
        session.commit()
    except:
        session.rollback()
        raise

查询示例:

with session_scope() as session:
    entity = session.query(SomeEntity).first()


失败的代码示例:

使 session 与 DB 一起工作的函数:

def create_session():
    # connect method the same as in first example
    con, meta = connect(db_user, db_pass, db_instance, 'localhost')
    Session = sessionmaker(bind=con)

    session = Session()
    return session

查询示例:

session = create_session()
entity = session.query(SomeEntity).first()


希望你明白了主要思想

最佳答案

首先,您不应在 connect() 函数中重复创建引擎。 usual practice is to have a single global Engine instance per database URL在你的应用程序中。 sessionmaker() 创建的 Session 类也是如此。

  1. What exactly does context manager do with connections and sessions? Closing session and disposing connection or what?

您将其编程为做什么,如果这看起来不清楚,read about context managers in general .在这种情况下它 commitsrolls back如果在 with 语句控制的 block 内引发异常,则 session 。这两个操作都将 session 使用的连接返回到池中,在您的情况下是 NullPool , 所以连接被简单地关闭了。

  1. Why does first working example of code behave as example with issue without NullPool as poolclass in "connect" method?

from sqlalchemy.pool import NullPool  # does not work without NullPool, why?

如果没有 NullPool,您重复创建的引擎也会将连接池化,因此如果它们出于某种原因没有超出范围,或者它们的引用计数没有清零,它们甚至会保留连接如果 session 返回它们。在第二个示例中, session 是否及时超出范围尚不清楚,因此它们也可能会保留连接。

  1. Why in the first example I got only 1 connection to db for all queries but in second example I got separate connection for each query? (please correct me if I understood it wrong, was checking it with "pgbouncer")

由于使用了正确处理事务的上下文管理器和 NullPool,第一个示例最终关闭了连接,因此连接返回到另一个池层 bouncer。

第二个示例可能永远不会关闭连接,因为它缺少事务处理,但由于给出的示例,这还不清楚。它还可能保持您创建的单独引擎中的连接。

"Session Basics" 中的官方文档几乎涵盖了问题集的第 4 点。 , 特别是 "When do I construct a Session, when do I commit it, and when do I close it?""Is the session thread-safe?" .

只有一个异常(exception):脚本的多个实例。您不应该在进程之间共享引擎,因此为了在它们之间建立连接池,您需要一个外部池,例如 PgBouncer。

关于python - SQLAlchemy - 使用与数据库和 session 的连接(不明确的行为和文档中的部分),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51124725/

相关文章:

python - SQLAlchemy 中使用的 "SQL Expression Language"是否支持 IN 运算符?

python - Pandas DataFrame 到列表列表的字典

python - 编辑距离字符串和列表

python - numpy 中是否有函数可以替换 numpy 数组的下对角线和上对角线值?

vba - 获取pgsql变量进入VB参数函数

ruby-on-rails - 远程服务器上的 Postgres 语言环境错误

python - 检查类名(字符串)是否用于 Python 中的某个类

SQL:ENUM 与一对多关系的优势?

python - SQLAlchemy 查询 - 它们什么时候执行?

python - 如何使用 Flask-SQLAlchemy 仅选择数据库中的某些列?