欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python流式游標(biāo)與緩存式(默認(rèn))游標(biāo)的那些坑及解決

 更新時(shí)間:2024年07月18日 09:17:38   作者:有人找你  
這篇文章主要介紹了Python流式游標(biāo)與緩存式(默認(rèn))游標(biāo)的那些坑及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一. 起因

本問(wèn)題起源于自己在服務(wù)器大量解析圖片數(shù)據(jù)。

運(yùn)行過(guò)程中出現(xiàn)錯(cuò)誤:

(2013, 'Lost connection to MySQL server during query')

因?yàn)檫@個(gè),我很認(rèn)真的仔細(xì)的查了Mysql有關(guān)的timeout的問(wèn)題:見(jiàn)“Mysql的timeout 以及 python重連”。

最后排查自己的問(wèn)題不出在connect_time(兩個(gè)sql語(yǔ)句之間的等待時(shí)間),而在于我在不斷獲取下一排數(shù)據(jù)項(xiàng)(即調(diào)用fetchone()方法)中間進(jìn)行大量耗時(shí)的工作,導(dǎo)致超過(guò)net_write_time而連接自動(dòng)斷開(kāi)。

原代碼:

	#這是一個(gè)類方法里面的內(nèi)容,簡(jiǎn)化版
  			sql = "select * from storys"
        try:
            # 獲取一個(gè)鏈接,一個(gè)cursor,執(zhí)行SQL語(yǔ)句,MysqlController為封裝的數(shù)據(jù)庫(kù)連接池處理工具
            conn = MysqlController.getConn()
            cursor = conn.cursor()
            cursor.execute(sql)

            #信號(hào)鎖
            semaphore = threading.BoundedSemaphore(self.maxRunThread)

            while(True):
                result = cursor.fetchone()
                if not result:
                    break
#這里不是重點(diǎn)
#———————————————————————————————————————————————————————————————————————————————————————————
                #這是一個(gè)for循環(huán),里面開(kāi)啟了10個(gè)線程,每次開(kāi)啟線程之前要求獲得到信號(hào)鎖。
  							#每個(gè)線程run方法結(jié)束之后會(huì)調(diào)用semaphore.release(),以此保證同時(shí)運(yùn)行的線程不超過(guò)self.maxRunThread個(gè)
                for i in range(10):
                    semaphore.acquire()
                    t = threading.Thread(target=self.run, args=(semaphore,i))
                    t.start()
#———————————————————————————————————————————————————————————————————————————————————————————

            print('結(jié)束')
            cursor.close()
            conn.close()
        except Exception as e:
            print(e)

但是非常奇怪的是,盡管報(bào)錯(cuò)Lost connection,但是我之后的數(shù)據(jù)依舊取到了,并完成分析了。

于是我做了一個(gè)小測(cè)試:

我預(yù)計(jì)取10個(gè)數(shù)據(jù),在取第3個(gè)數(shù)據(jù)的時(shí)候,手動(dòng)把連接斷開(kāi)了。

按照我之前對(duì)fetchone()的理解,是每一次cursor在mysql中下移一個(gè)位置,返回給客戶端。

如果連接一旦斷開(kāi),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()

但是結(jié)果:

python3 run.py
23
24
25
connection is close
26
...

可以看見(jiàn),手動(dòng)關(guān)閉連接后,cursor依舊能取到數(shù)據(jù)。

最后結(jié)論:dbq,是我菜了,這個(gè)是假的fetchone。

二. 正事兒

經(jīng)過(guò)查詢,python中的cursor主要分為兩大類:

非緩存式游標(biāo)和緩存式游標(biāo)。

cursor = connection.cursor()

這種方法默認(rèn)的是緩存式游標(biāo),緩存式游標(biāo)顧名思義,不管是fetchone還是fetchall都是在執(zhí)行語(yǔ)句的時(shí)候一次性返回所有數(shù)據(jù)到客戶端。

這種返回在數(shù)據(jù)量特別大的時(shí)候無(wú)疑是不利的,會(huì)占用大量?jī)?nèi)存,導(dǎo)致我的主機(jī)卡成ppt。

最正確的用法是使用非緩存式游標(biāo),即流式游標(biāo)(SSCursor也可以):

cursor = conn.cursor(pymysql.cursors.SSDictCursor)#返回字典式數(shù)據(jù)

三. 小石子Warning

在查明白cursor的區(qū)別后,我非常開(kāi)心的把游標(biāo)換了。

但由于之前曾經(jīng)處理過(guò)timeout的問(wèn)題,我曾經(jīng)非常多此一舉的在代碼里面添加過(guò)ping():

	#這是一個(gè)類方法里面的內(nèi)容,簡(jiǎn)化版
  			sql = "select * from storys"
        try:
            # 獲取一個(gè)鏈接,一個(gè)cursor,執(zhí)行SQL語(yǔ)句,MysqlController為封裝的數(shù)據(jù)庫(kù)連接池處理工具
            conn = MysqlController.getConn()
            cursor = conn.cursor(pymysql.cursors.SSDictCursor)#這里改游標(biāo)類型了?。。。。。?!
            cursor.execute(sql)

            while(True):
              	conn.ping()# 就是這句話?。。。。。。。?!畫蛇添足?。。。。。?!正確代碼去掉這句話
                result = cursor.fetchone()
                if not result:
                    break
								#做了一些事兒

            print('結(jié)束')
            cursor.close()
            conn.close()
        except Exception as e:
            print(e)

要知道,在一個(gè)循環(huán)的不斷取數(shù)據(jù)的過(guò)程中,如果使用了ping就會(huì)使之前的查詢斷掉。

于是報(bào)錯(cuò):

UserWarning: Previous unbuffered result was left incomplete warnings.warn("Previous unbuffered result was left incomplete")

這個(gè)是由于查詢未完成而造成的,去掉ping就好了。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論