【问题标题】:Does SQLAlchemy reset the database session between SQLAlchemy Sessions from the same connection?SQLAlchemy 是否从同一连接重置 SQLAlchemy 会话之间的数据库会话?
【发布时间】:2021-11-15 04:24:32
【问题描述】:

SQLAlchemy 利用连接池。这意味着可以在不同的 SQLAlchemy 会话中重用相同的连接。但是,单个 SQLAlchemy 会话包含在其自身中,并在关闭后被丢弃。但是,连接保持“活动”。

我想使用 set_config 将一些内容保存到 Postgresql 中的数据库会话存储中:

PERFORM set_config('session.storage', 'remember-me-across-this-session', false)

现在,这是在数据库会话的范围内。我的问题是:当 SQLAlchemy 使用相同的连接创建一个新的 SQLAlchemy 会话时,这是否也会创建一个新的数据库会话,或者连接会在其生命周期内重复使用相同的数据库会话吗?

注意: 我已经尝试通过将所有相关池大小设置为最小值(max_overflow 0、pool_size 1、pool_recycle 600)然后运行以下脚本(简化)来测试这一点:

print(DBSESSION.execute(text("SELECT set_config('session.storage', 'remember-me-across-this-session', false)")).first())
print(DBSESSION.execute(text("SELECT current_setting('session.storage')")).first())
transaction.commit()
DBSESSION.close()

for _ in range(5):
    print(DBSESSION.execute(text("SELECT current_setting('session.storage')")).first())
    transaction.commit()
    DBSESSION.close()

此测试没有“记住”循环中后续会话的第一行中设置的值,因此确认数据库会话确实在同一连接的 SQLAlchemy 会话之间重置。然而,因为这是逻辑的关键部分,我希望得到第二个意见/肯定,以确保我没有搞砸。

【问题讨论】:

    标签: python postgresql session sqlalchemy


    【解决方案1】:

    1。 SQLAlchemy 是否重置数据库会话?

    不,它没有。

    1.1。关于 SQLAlchemy 会话

    SQLAlchemy session.close() 关闭剩余的 SQLAlchemy 事务,这些事务在其连接上调用 ROLLBACK 并将它们返回到池中。

    来自How to close a SQLAlchemy session

    SQLAlchemy 会话通常表示在特定数据库连接上一个或多个事务的范围。

    1.2。关于 PostgreSQL 会话

    来自How do I find out the numeric ID of the current Postgres Transaction

    会话是“TCP 连接的同义词”。

    1.3。关于PostgreSQLSET

    来自https://www.postgresql.org/docs/9.3/sql-set.html

    如果在稍后中止的事务中发出SET(或等效的SET SESSION),则在回滚事务时,SET 命令的效果会消失。提交周围事务后,效果将持续到会话结束,除非被另一个 SET 覆盖。

    2。为什么问题中的测试有效?

    在测试中,没有任何操作导致 Zope 将会话状态标记为已更改。

    Zope transaction.commit() 检查会话状态是否改变:

    • 如果不是,它调用 SQLAlchemy session.close() 并将其对 SQLAlchemy 事务的引用设置为 None
      • 1.1 中所述。关于 SQLAlchemy 会话,这会在连接上调用 ROLLBACK
        • 1.3 中所述。关于PostgreSQL SETSET 命令的效果消失了。
    • 否则,它会提交 SQLAlchemy 事务。
      • 1.3 中所述。关于 PostgreSQL SET,效果将持续到(PostgreSQL)会话结束。

    您可以通过将会话显式标记为已更改来验证 Else 案例:

    print(DBSESSION.execute(text("SELECT set_config('session.storage', 'remember-me-across-this-session', false)")).first())
    print(DBSESSION.execute(text("SELECT current_setting('session.storage')")).first())
    mark_changed(DBSESSION.registry())  # Add this
    transaction.commit()
    

    注意:由于transaction.commit()transaction.abort() 已经隐式调用session.close(),随后对DBSESSION.close() 的调用实际上什么都不做。

    3。如何重置会话运行时参数?

    sqlalchemy.events.PoolEvents.checkin 添加一个事件监听器并调用RESET

    @event.listens_for(engine, 'checkin')
    def receive_checkin(dbapi_connection, connection_record):
        cursor = dbapi_connection.cursor()
        cursor.execute('RESET session.storage')
        # cursor.execute('RESET ALL')
    

    【讨论】:

    • 很好的答案。非常感谢!
    猜你喜欢
    • 2014-07-08
    • 2011-07-29
    • 2016-12-25
    • 1970-01-01
    • 2013-08-26
    • 1970-01-01
    • 2016-10-17
    • 1970-01-01
    • 2016-03-23
    相关资源
    最近更新 更多