python pymysql multiprocessing.dummy多线程 读写数据库报错
文章目录
- 一、例子
- 二、报错及原因
- 三、解决方法
- 1.在每个execute前加上互斥锁
- 2.在pool1.map(func, list)中参数的func函数中,实例化一个数据库对象
- 3.在KsMySql数据库链接类中使用数据库链接池获取链接,将pool链接池为类对象
一、例子
- 需求
使用多线程下载视频到本地,将视频的名字保存在数据库表中,数据库表中不能保存重复视频名字 - demo.py
from multiprocessing.dummy import Pool
import traceback
import requests
import pymysql
import os
# 习惯函数名开头大写,变量名开头小写,还没适应Python写代码规范,见谅# 数据库链接类
class KsMySql:def __init__(self):self.conn = pymysql.Connect(host='127.0.0.1', port=3306, user='root', password='1234567', db='pythonspider', charset='utf8mb4') # 普通链接self.cursor = self.conn.cursor()# 是否保存过了通过视频名称查找, 返回true为不存在,false为存在def IsSaveVideoByName(self, filename):try:self.cursor.execute('select * from ksvideoinfo where filename = "%s"' %(filename))result = self.cursor.fetchone()return result is not Noneexcept:print('IsSaveVideoByName 查询错误')traceback.print_exc()return True# 插入视频信息def SaveVideoInfo(self, filename):try:self.cursor.execute('insert into ksvideoinfo(filename) values("%s")'%(filename))self.conn.commit()print('SaveVideoInfo 插入数据成功')except Exception as e:self.conn.rollback()print('SaveVideoInfo 插入数据错误')print(e)traceback.print_exc()def __del__(self):self.cursor.close()self.conn.close()# 全局变量
ksmysql = KsMySql()# 数据库类实例
infolist = []
dirName = 'E:/AllWorkSpace1/Pytharm/pythonProjectPaWeb/Testdemo'# 保存目录
if not os.path.exists(dirName):os.mkdir(dirName)def Select():name = '杨洋迪丽热巴《烟火星辰》,用歌声致敬中国航天'# 需求3:数据库表中不能保存重复视频名字(这里只是模拟)isSave = ksmysql.IsSaveVideoByName(name)# 为了方便,默认为不存在,直接添加url到list中mp4url = 'https://video.pearvideo.com/mp4/short/20220206/cont-1751191-15823342-hd.mp4'infolist.append({'name': name, 'videoUrl': mp4url})def SaveInfo(dic):name = dic['name']pathName = dirName + '/' + name + '.mp4'url = dic['videoUrl']try:# if not os.path.exists(pathName):mp4Data = requests.get(url=url).content # 从网络下载视频with open(pathName, 'wb') as f:# 需求1:视频保存在本地f.write(mp4Data)print(name, "下载完成")# else:# print(name,'已存在,无需下载')# 需求2:视频的名字保存在数据库表中ksmysql.SaveVideoInfo(name)except Exception as e:print(name, '下载失败失败或者保存数据库失败')print(e)traceback.print_exc()def Main():pool1 = Pool(20) # 线程池for cur in range(0, 100):infolist.clear()Select()pool1.map(SaveInfo, infolist) # 使用多线程下载pool1.close()pool1.join()Main()
二、报错及原因
- 常见错误
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,是因为各个线程共享同一个数据库链接而导致的错误
三、解决方法
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
...同上
但经过我个人测试发现,没有用,还是会报新错,这个方法理论上是没问题的,但是在multiprocessing.dummy多线程情况下却不行。仅代表我个人想法,也许自己能力不足,哪里写错了
2.在pool1.map(func, list)中参数的func函数中,实例化一个数据库对象
...
def SaveInfo(dic):ksmysql = KsMySql()# 数据库类实例name = dic['name']pathName = dirName + '/' + name + '.mp4'url = dic['videoUrl']try:# if not os.path.exists(pathName):mp4Data = requests.get(url=url).content # 从网络下载视频with open(pathName, 'wb') as f:# 需求1:视频保存在本地f.write(mp4Data)print(name, "下载完成")# else:# print(name,'已存在,无需下载')# 需求2:视频的名字保存在数据库表中ksmysql.SaveVideoInfo(name)except Exception as e:print(name, '下载失败失败或者保存数据库失败')print(e)traceback.print_exc()
...
可以完美解决,因为这样每个线程都有自己的数据库链接对象。
优点:简单、方便
缺点:每调用SaveInfo函数一次就建立一个数据库链接,并函数结束时关闭链接,可能性能有损
3.在KsMySql数据库链接类中使用数据库链接池获取链接,将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()# 静态方法@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实例,从数据库链接池获取链接')return KsMySql.pool.connection()...def __del__(self):# 链接不是真正的被关闭,而是放回链接池中self.cursor.close()self.conn.close()def SaveInfo(dic):ksmysql = KsMySql()# 同样要写上实例化数据库类对象...
...
注意
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参数,代表当链接都被占用了,是否等待新的空闲链接
True :等待, 可能影响程序速度
False:不等待,(个人猜测。。好像是代表同用已占有的数据库链接对象,会重复一开始的报错),反正会报错,最好写成True
'''
可以完美解决,因为这样每个线程也都有自己的数据库链接对象。
优点:从链接池中获取自己的链接,优化点性能把
缺点:代码稍微复杂,坑多。。。
python pymysql multiprocessing.dummy多线程 读写数据库报错相关推荐
- python pymysql 多线程 读写数据库 报错 Packet sequence number wrong
多线程连接数据,提交增改查请求,爆出Packet sequence number wrong - got 7 expected 2(数据包序列号错误) 原因:这是因为多线程共享了同一个数据库连接,但每 ...
- python 多进程multiprocessing进程池pool tensorflow-yolov3 报错 MemoryError
进程数设置为1-9个都能正常运行,设置成10个就开始报错,怪事! D:\20191031_tensorflow_yolov3\python\python.exe D:/20191031_tensorf ...
- python 多进程multiprocessing进程池pool tensorflow-yolov3 报错TypeError: 'ApplyResult' object is not iterable
首先,代码结构它长这样: 可每次调用线程池进行识别时,就会报如下错误: D:\20191031_tensorflow_yolov3\python\python.exe D:/20191031_tens ...
- 多线程执行sql报错处理
pymysql多线程访问数据库报错:Packet sequence number wrong - got 7 expected 2 原文:https://www.cnblogs.com/heiao10 ...
- 关于MAC下pymysql连接mysql数据库报错2003的问题解决方法
关于MAC下pymysql连接mysql数据库报错2003的问题解决方法 问题:pymysql.err.OperationalError: (2003, "Can't connect to ...
- Python连接mysql,插入数据时不报错,但是没有插入进去
Python连接mysql,插入数据时不报错,但是没有插入进去在connect方法中,设置 autocommit =True conn=pymysql.connect(host=host_db,use ...
- Pycharm连接mysql数据库报错1130,1054
Pycharm连接并创建mysql数据库报错 1.报错信息如下mysql.connector.errors.NotSupportedError: Authentication plugin 'cach ...
- Navicat链接数据库报错1130解决方案
Navicat链接数据库报错1130解决方案 参考文章: (1)Navicat链接数据库报错1130解决方案 (2)https://www.cnblogs.com/newAndHui/p/113451 ...
- OpenStack在keystone部分同步数据库报错Errno 13解决办法
OpenStack在keystone部分同步数据库报错Errno 13 在执行 su -s /bin/sh -c "keystone-manage db_sync" keyston ...
- mysql数据库报错1146_关于MySQL报错:[ERR] 1146
最近因为电脑重装了系统,导致自己原本的数据库呗覆盖,需要重新重新安装数据库,但是由于我之前数据库版本是mysql 5.0.22,版本太低,所以小编决定安装mysql 5.7.23版本的,一开始没什么问 ...
最新文章
- Java内存模型深度剖析
- 笔记-高项案例题-2018年上-质量管理
- linux下的定时任务处理
- 关于linux的进程和线程
- mysql innodb数据结构_Mysql InnoDB数据结构
- macOS Docker 上安装、启动 MySQL
- 高效延时消息设计与实现的场景
- win10安装影子系统,导致电脑无限蓝屏,解决总结
- 系统架构设计笔记(91)—— 安全性规章
- VS2017安装WTL,解决创建WTL项目一直回弹问题
- SMS发送流程 Android2.2
- 解决克隆虚拟机后无法上网问题(亲测有效)
- Tensorflow2——Eager模式简介以及运用
- Java每日一练(4)
- 碳中和大潮惊涛拍岸,科技企业如何迈入这条大江大河?
- 【编译原理】交叉工具链详解
- 【密码算法 之七】GCM 浅析
- 爬虫:爬取糗事百科数据
- Java实验——定义一个类,该类中包含以下几个方法(静态):实现两个字符串数组的逆序排序,输出结果为字符串数组;求两个整形数组的交集;求两个浮点型数组的并集;
- java实现老鼠出迷宫