關於flask-sqlalchemy的用法研究

最近使用到flask的sqlalchemy,由於flask對sqlalchemy作了一些封裝,加上本身自己對sqlalchemy也不熟悉,用法上走了不少彎路。python

由於沒時間去研究sqlalchemy的源碼,因此只能簡單的測試下用法。sql

一、flask-sqlalchemy是線程安全的數據庫

  具體能夠參考文章 https://blog.csdn.net/luffyser/article/details/89380186flask

 

二、每次查詢完之後,記得commit,否則會佔用鏈接池緩存

  我在本地作了個簡單的測試,若是單次查詢請求完,不commit的話,連續請求幾回,再發起request就沒有響應了,推測是數據庫鏈接池沒釋放,被佔用。致使請求數據庫掛起,從而致使沒有response。安全

      每次請求完,直接commit,能夠解決此問題。  session

    def queryLast(cls):
        try:
            ret = db.session.query(cls).order_by(cls.version.desc()).first()
       #db.session.expunge(ret) db.session.commit() except: db.session.rollback() ret = None return ret

 

三、可是,若是Commit後,查詢結果可能會從緩存中清掉,若是再使用查詢結果的對象,還會再次創建鏈接查詢。因此還會出現上述鏈接池耗盡的問題。app

   從下圖標黃的日誌能夠看出,commit後,使用返回的查詢結果時,又執行了一次查詢任務,並返回結果,my god!測試

2019-12-10 12:31:21,650 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-12-10 12:31:21,651 INFO sqlalchemy.engine.base.Engine SELECT appversion.id AS appversion_id, appversion.version AS appversion_version, appversion.`appUrl` AS `appversion_appUrl`, appversion.des AS appversion_des, appversion.`createTime` AS `appversion_createTime`, appversion.`lastModiftyTime` AS `appversion_lastModiftyTime`, appversion.type AS appversion_type 
FROM appversion ORDER BY appversion.version DESC 
 LIMIT %s
2019-12-10 12:31:21,651 INFO sqlalchemy.engine.base.Engine (1,)
2019-12-10 12:31:21,661 INFO sqlalchemy.engine.base.Engine COMMIT
2019-12-10 12:31:21,680 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 2019-12-10 12:31:21,681 INFO sqlalchemy.engine.base.Engine SELECT appversion.id AS appversion_id, appversion.version AS appversion_version, appversion.`appUrl` AS `appversion_appUrl`, appversion.des AS appversion_des, appversion.`createTime` AS `appversion_createTime`, appversion.`lastModiftyTime` AS `appversion_lastModiftyTime`, appversion.type AS appversion_type FROM appversion WHERE appversion.id = %s 2019-12-10 12:31:21,681 INFO sqlalchemy.engine.base.Engine (1,)

四、但有時候(多是時間略長些)commit後,再使用查詢結果的對象,可能會出現報錯:Instance <User at 0x32768d0> is not bound to a Session   spa

  此種狀況多是由於綁定的session已經被回收,致使沒法再進行查詢,因此出錯。

 

五、綜上所述,爲安全起見,須要在查詢結果後,加上 db.session.expunge(ret),斷開查詢結果與session的關係。讓它成爲一個本地實體,不會從緩存中清除,使用時候,就不會再查詢。

六、但測試時候發現一個奇怪的問題,另一個獲取user的接口,和上面的代碼幾乎沒什麼區別,竟然會自動rollback,這個讓我百思不得其解。

  個人邏輯是取到查詢結果(即用戶)後,判斷用戶的狀態字段是否爲1,若是爲1,就修改用戶屬性,而後commit,若是不是1,就不作操做,也沒有調用rollback。

  可是我測試時候發現,若是不是1的時候,它會自動rollback。

        或許這是sqlalchemy的高級功能?

 

七、總結:

  一、sqlalchemy的對象實體(model),和session創建了聯繫,你get、set這些model的時候,就算已經commit,也會從新自動和數據庫創建鏈接(get的時候會從新select、set的時候會從新創建鏈接,等待你提交,若是你不提交,這個鏈接一直存在,最終會耗盡。),因此要謹慎使用model的字段,除非你確實明白本身在作什麼,會發生什麼。

  二、使用db.session.expunge會切斷實體和session的關係。這個是個不錯的用法。

  三、但我仍是強烈建議本身再搞一套model,來作業務層邏輯。sqlalchemy的對象實體僅用來作數據庫的操做。這樣會避免不少時候,鏈接不當心沒釋放的坑。

相關文章
相關標籤/搜索