python pymysql multiprocessing.dummy多线程 读写数据库报错
生活随笔
收集整理的這篇文章主要介紹了
python pymysql multiprocessing.dummy多线程 读写数据库报错
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章目錄
- 一、例子
- 二、報錯及原因
- 三、解決方法
- 1.在每個execute前加上互斥鎖
- 2.在pool1.map(func, list)中參數(shù)的func函數(shù)中,實例化一個數(shù)據(jù)庫對象
- 3.在KsMySql數(shù)據(jù)庫鏈接類中使用數(shù)據(jù)庫鏈接池獲取鏈接,將pool鏈接池為類對象
一、例子
- 需求
使用多線程下載視頻到本地,將視頻的名字保存在數(shù)據(jù)庫表中,數(shù)據(jù)庫表中不能保存重復視頻名字 - demo.py
二、報錯及原因
- 常見錯誤
1). Packet sequence number wrong
2). Exception _mysql_exceptions.OperationalError: (2013, ‘Lost connection to MySQL server during query’)
3). pymysql AttributeError: ‘NoneType‘ object has no attribute ‘settimeout‘ - 原因
如上demo.py,是因為各個線程共享同一個數(shù)據(jù)庫鏈接而導致的錯誤
三、解決方法
1.在每個execute前加上互斥鎖
如:
...同上 import threading class KsMySql:def __init__(self):self.conn = pymysql.Connect(host='127.0.0.1', port=3306, user='root', password='tiger', db='pythonspider', charset='utf8mb4') # 普通鏈接self.cursor = self.conn.cursor()self.lock = threading.Lock()# 實例化# 是否保存過了通過視頻名稱查找, 返回true為不存在,false為存在def IsSaveVideoByName(self, filename):try:self.lock.acquire() # 上鎖self.cursor.execute('select * from ksvideoinfo where filename = "%s"' %(filename))result = self.cursor.fetchone()self.lock.release() # 解鎖return result is not Noneexcept:print('IsSaveVideoByName 查詢錯誤')traceback.print_exc()return True ...同上但經(jīng)過我個人測試發(fā)現(xiàn),沒有用,還是會報新錯,這個方法理論上是沒問題的,但是在multiprocessing.dummy多線程情況下卻不行。僅代表我個人想法,也許自己能力不足,哪里寫錯了
2.在pool1.map(func, list)中參數(shù)的func函數(shù)中,實例化一個數(shù)據(jù)庫對象
... def SaveInfo(dic):ksmysql = KsMySql()# 數(shù)據(jù)庫類實例name = dic['name']pathName = dirName + '/' + name + '.mp4'url = dic['videoUrl']try:# if not os.path.exists(pathName):mp4Data = requests.get(url=url).content # 從網(wǎng)絡(luò)下載視頻with open(pathName, 'wb') as f:# 需求1:視頻保存在本地f.write(mp4Data)print(name, "下載完成")# else:# print(name,'已存在,無需下載')# 需求2:視頻的名字保存在數(shù)據(jù)庫表中ksmysql.SaveVideoInfo(name)except Exception as e:print(name, '下載失敗失敗或者保存數(shù)據(jù)庫失敗')print(e)traceback.print_exc() ...可以完美解決,因為這樣每個線程都有自己的數(shù)據(jù)庫鏈接對象。
優(yōu)點:簡單、方便
缺點:每調(diào)用SaveInfo函數(shù)一次就建立一個數(shù)據(jù)庫鏈接,并函數(shù)結(jié)束時關(guān)閉鏈接,可能性能有損
3.在KsMySql數(shù)據(jù)庫鏈接類中使用數(shù)據(jù)庫鏈接池獲取鏈接,將pool鏈接池為類對象
... from dbutils.pooled_db import PooledDBclass KsMySql:pool = Nonedef __init__(self):# self.conn = pymysql.Connect(host='127.0.0.1', port=3306, user='root', password='tiger', db='pythonspider', charset='utf8mb4') # 普通鏈接,每實例化一個對象就會新建一個鏈接self.conn = KsMySql.Getmysqlconn()# 從鏈接池中獲取鏈接self.cursor = self.conn.cursor()# 靜態(tài)方法@staticmethoddef Getmysqlconn():if KsMySql.pool is None:mysqlInfo = {"host": '127.0.0.1',"user": 'root',"passwd": 'tiger',"db": 'pythonspider',"port": 3306,"charset": 'utf8mb4'}KsMySql.pool = PooledDB(creator=pymysql, mincached=1, maxcached=20, host=mysqlInfo['host'],user=mysqlInfo['user'], passwd=mysqlInfo['passwd'], db=mysqlInfo['db'],port=mysqlInfo['port'], charset=mysqlInfo['charset'], blocking=True)print(KsMySql.pool)# else:# print('新KsMySql實例,從數(shù)據(jù)庫鏈接池獲取鏈接')return KsMySql.pool.connection()...def __del__(self):# 鏈接不是真正的被關(guān)閉,而是放回鏈接池中self.cursor.close()self.conn.close()def SaveInfo(dic):ksmysql = KsMySql()# 同樣要寫上實例化數(shù)據(jù)庫類對象... ...注意
KsMySql.pool = PooledDB(creator=pymysql, mincached=1, maxcached=20, host=mysqlInfo['host'],user=mysqlInfo['user'], passwd=mysqlInfo['passwd'], db=mysqlInfo['db'],port=mysqlInfo['port'], charset=mysqlInfo['charset'], blocking=True) ''' blocking參數(shù),代表當鏈接都被占用了,是否等待新的空閑鏈接 True :等待, 可能影響程序速度 False:不等待,(個人猜測。。好像是代表同用已占有的數(shù)據(jù)庫鏈接對象,會重復一開始的報錯),反正會報錯,最好寫成True '''可以完美解決,因為這樣每個線程也都有自己的數(shù)據(jù)庫鏈接對象。
優(yōu)點:從鏈接池中獲取自己的鏈接,優(yōu)化點性能把
缺點:代碼稍微復雜,坑多。。。
總結(jié)
以上是生活随笔為你收集整理的python pymysql multiprocessing.dummy多线程 读写数据库报错的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序文件关联的修复
- 下一篇: linux cmake编译源码,linu