簡體   English   中英

SQLAlchemy 是否會重置來自同一連接的 SQLAlchemy 會話之間的數據庫會話?

[英]Does SQLAlchemy reset the database session between SQLAlchemy Sessions from the same connection?

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. SQLAlchemy 會重置數據庫會話嗎?

不,不是的。

1.1. 關於 SQLAlchemy 會話

SQLAlchemy session.close()關閉剩余的 SQLAlchemy 事務,這些事務在它們的連接上調用ROLLBACK並將它們返回到池中。

如何關閉 SQLAlchemy 會話

一個 SQLAlchemy Session 通常代表一個或多個事務的范圍,在特定的數據庫連接上。

1.2. 關於 PostgreSQL 會話

如何找出當前 Postgres 事務的數字 ID

會話“與 TCP 連接同義”。

1.3. 關於 PostgreSQL SET

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

如果SET (或等效的SET SESSION )在稍后被中止的事務中發出,則SET命令的效果在事務回滾時消失。 一旦周圍的事務被提交,效果將持續到會話結束,除非被另一個SET覆蓋。

2. 題中的測試為什么有效?

在測試中,沒有任何操作導致 Zope 將會話狀態標記為已更改。

Zope transaction.commit()檢查會話狀態是否改變:

  • 如果不是,則調用 SQLAlchemy session.close()並將其對 SQLAlchemy Transaction 的引用設置為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')

暫無
暫無

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

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