SQLAlchemy 是不是从同一连接重置 SQLAlchemy 会话之间的数据库会话?

Posted

技术标签:

【中文标题】SQLAlchemy 是不是从同一连接重置 SQLAlchemy 会话之间的数据库会话?【英文标题】: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 会话之间重置。然而,因为这是逻辑的关键部分,我希望得到第二个意见/肯定,以确保我没有搞砸。

【问题讨论】:

【参考方案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')

【讨论】:

很好的答案。非常感谢!

以上是关于SQLAlchemy 是不是从同一连接重置 SQLAlchemy 会话之间的数据库会话?的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy 仅从连接表中选择列

无法使用 sqlalchemy 建立连接 SQL Server

SQL Alchemy奇怪的行为从同一个表中加入多个列

python连接数据库使用SQLAlchemy

从 SQLAlchemy 中的文件执行 SQL

SQLAlchemy 连接来自同一个表的多个列