Python流式游標與緩存式(默認)游標的那些坑及解決
一. 起因
本問題起源于自己在服務器大量解析圖片數(shù)據(jù)。
運行過程中出現(xiàn)錯誤:
(2013, 'Lost connection to MySQL server during query')
因為這個,我很認真的仔細的查了Mysql有關的timeout的問題:見“Mysql的timeout 以及 python重連”。
最后排查自己的問題不出在connect_time(兩個sql語句之間的等待時間),而在于我在不斷獲取下一排數(shù)據(jù)項(即調用fetchone()方法)中間進行大量耗時的工作,導致超過net_write_time而連接自動斷開。
原代碼:
#這是一個類方法里面的內容,簡化版 sql = "select * from storys" try: # 獲取一個鏈接,一個cursor,執(zhí)行SQL語句,MysqlController為封裝的數(shù)據(jù)庫連接池處理工具 conn = MysqlController.getConn() cursor = conn.cursor() cursor.execute(sql) #信號鎖 semaphore = threading.BoundedSemaphore(self.maxRunThread) while(True): result = cursor.fetchone() if not result: break #這里不是重點 #——————————————————————————————————————————————————————————————————————————————————————————— #這是一個for循環(huán),里面開啟了10個線程,每次開啟線程之前要求獲得到信號鎖。 #每個線程run方法結束之后會調用semaphore.release(),以此保證同時運行的線程不超過self.maxRunThread個 for i in range(10): semaphore.acquire() t = threading.Thread(target=self.run, args=(semaphore,i)) t.start() #——————————————————————————————————————————————————————————————————————————————————————————— print('結束') cursor.close() conn.close() except Exception as e: print(e)
但是非常奇怪的是,盡管報錯Lost connection,但是我之后的數(shù)據(jù)依舊取到了,并完成分析了。
于是我做了一個小測試:
我預計取10個數(shù)據(jù),在取第3個數(shù)據(jù)的時候,手動把連接斷開了。
按照我之前對fetchone()的理解,是每一次cursor在mysql中下移一個位置,返回給客戶端。
如果連接一旦斷開,cursor就不能獲取到數(shù)據(jù)了。
import pymysql import time def mytest(): connection = pymysql.connect( host='localhost', port=3306, user='root', password='', db='*******', charset='utf8') cursor = connection.cursor() cursor.execute("select * from storys limit 10") data = cursor.fetchone() i = 0 while data != None: if(i == 3): connection.close() print('connection is close') print(data[0]) i+=1 data = cursor.fetchone() cursor.close() connection.close() if __name__ == '__main__': mytest()
但是結果:
python3 run.py
23
24
25
connection is close
26
...
可以看見,手動關閉連接后,cursor依舊能取到數(shù)據(jù)。
最后結論:dbq,是我菜了,這個是假的fetchone。
二. 正事兒
經(jīng)過查詢,python中的cursor主要分為兩大類:
非緩存式游標和緩存式游標。
cursor = connection.cursor()
這種方法默認的是緩存式游標,緩存式游標顧名思義,不管是fetchone還是fetchall都是在執(zhí)行語句的時候一次性返回所有數(shù)據(jù)到客戶端。
這種返回在數(shù)據(jù)量特別大的時候無疑是不利的,會占用大量內存,導致我的主機卡成ppt。
最正確的用法是使用非緩存式游標,即流式游標(SSCursor也可以):
cursor = conn.cursor(pymysql.cursors.SSDictCursor)#返回字典式數(shù)據(jù)
三. 小石子Warning
在查明白cursor的區(qū)別后,我非常開心的把游標換了。
但由于之前曾經(jīng)處理過timeout的問題,我曾經(jīng)非常多此一舉的在代碼里面添加過ping():
#這是一個類方法里面的內容,簡化版 sql = "select * from storys" try: # 獲取一個鏈接,一個cursor,執(zhí)行SQL語句,MysqlController為封裝的數(shù)據(jù)庫連接池處理工具 conn = MysqlController.getConn() cursor = conn.cursor(pymysql.cursors.SSDictCursor)#這里改游標類型了?。。。。。?! cursor.execute(sql) while(True): conn.ping()# 就是這句話?。。。。。。。?!畫蛇添足?。。。。。。≌_代碼去掉這句話 result = cursor.fetchone() if not result: break #做了一些事兒 print('結束') cursor.close() conn.close() except Exception as e: print(e)
要知道,在一個循環(huán)的不斷取數(shù)據(jù)的過程中,如果使用了ping就會使之前的查詢斷掉。
于是報錯:
UserWarning: Previous unbuffered result was left incomplete warnings.warn("Previous unbuffered result was left incomplete")
這個是由于查詢未完成而造成的,去掉ping就好了。
總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
如何解決Pycharm運行報錯No Python interpreter selected
這篇文章主要介紹了如何解決Pycharm運行時No Python interpreter selected問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05Python Django網(wǎng)頁界面協(xié)同過濾推薦算法實現(xiàn)商品管理與推薦
商品管理與推薦系統(tǒng),本系統(tǒng)使用Python作為主要開發(fā)語言,前端采用HTML、CSS、BootStrap等技術搭建顯示界面,后端采用Django框架處理用戶的請求響應2023-11-11MacOS(M1芯片 arm架構)下安裝PyTorch的詳細過程
這篇文章主要介紹了MacOS(M1芯片 arm架構)下安裝PyTorch的詳細過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-02-02Python基于輾轉相除法求解最大公約數(shù)的方法示例
這篇文章主要介紹了Python基于輾轉相除法求解最大公約數(shù)的方法,結合實例形式分析了Python使用輾轉相除法求解最大公約數(shù)的實現(xiàn)方法與優(yōu)化操作技巧,需要的朋友可以參考下2018-04-04pycharm中下載的包但是import還是無法使用/報紅的解決方法
用pycharm開發(fā)時,在導入自己寫的python文件時出現(xiàn)模塊名爆紅的情況,下面這篇文章主要給大家介紹了關于pycharm中下載包但是import還是無法使用/報紅的解決方法,需要的朋友可以參考下2023-02-02