關於flask-sqlalchemy的用法研究


最近使用到flask的sqlalchemy,因為flask對sqlalchemy做了一些封裝,加上自己本身對sqlalchemy也不熟悉,用法上走了很多彎路。

因為沒時間去研究sqlalchemy的源碼,所以只能簡單的測試下用法。

1、flask-sqlalchemy是線程安全的

  具體可以參考文章 https://blog.csdn.net/luffyser/article/details/89380186

 

2、每次查詢完以后,記得commit,不然會占用連接池

  我在本地做了個簡單的測試,如果單次查詢請求完,不commit的話,連續請求幾次,再發起request就沒有響應了,推測是數據庫連接池沒釋放,被占用。導致請求數據庫掛起,從而導致沒有response。

      每次請求完,直接commit,可以解決此問題。  

    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

 

3、但是,如果Commit后,查詢結果可能會從緩存中清掉,如果再使用查詢結果的對象,還會再次建立連接查詢。所以還會出現上述連接池耗盡的問題。

   從下圖標黃的日志可以看出,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,)

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

  此種情況可能是因為綁定的session已經被回收,導致無法再進行查詢,所以出錯。

 

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

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

  我的邏輯是取到查詢結果(即用戶)后,判斷用戶的狀態字段是否為1,如果為1,就修改用戶屬性,然后commit,如果不是1,就不做操作,也沒有調用rollback。

  但是我測試時候發現,如果不是1的時候,它會自動rollback。

        或許這是sqlalchemy的高級功能?

 

7、總結:

  1、sqlalchemy的對象實體(model),和session建立了聯系,你get、set這些model的時候,就算已經commit,也會重新自動和數據庫建立連接(get的時候會重新select、set的時候會重新建立連接,等待你提交,如果你不提交,這個連接一直存在,最終會耗盡。),所以要謹慎使用model的字段,除非你確實明白自己在做什么,會發生什么。

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

  3、但我還是強烈建議自己再搞一套model,來做業務層邏輯。sqlalchemy的對象實體僅用來做數據庫的操作。這樣會避免很多時候,連接不小心沒釋放的坑。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM