京公网安备 11010802034615号
经营许可证编号:京B2-20210330
Python中MySQLdb和torndb模块对MySQL的断连问题处理
在使用python 对wordpress tag 进行细化代码处理时,遇到了调用MySQLdb模块时的出错,由于错误提示和问题原因相差甚远,查看了N久代码也未发现代码有问题。后来问了下师傅,被告知MySQLdb里有一个断接的坑 ,需要进行数据库重连解决。
一、报错代码及提示
运行出错的代码如下:
import MySQLdb
def getTerm(db,tag):
cursor = db.cursor()
query = "SELECT term_id FROM wp_terms where name=%s "
count = cursor.execute(query,tag)
rows = cursor.fetchall()
db.commit()
#db.close()
if count:
term_id = [int(rows[id][0]) for id in range(count)]
return term_id
else:return None
def addTerm(db,tag):
cursor = db.cursor()
query = "INSERT into wp_terms (name,slug,term_group) values (%s,%s,0)"
data = (tag,tag)
cursor.execute(query,data)
db.commit()
term_id = cursor.lastrowid
sql = "INSERT into wp_term_taxonomy (term_id,taxonomy,description) values (%s,'post_tag',%s) "
value = (term_id,tag)
cursor.execute(sql,value)
db.commit()
db.close()
return int(term_id)
dbconn = MySQLdb.connect(host='localhost', user='root', passwd='123456', db='361way', port=3306, charset='utf8', init_command='set names utf8')
tags = ['mysql','1111','aaaa','bbbb','ccccc','php','abc','python','java']
tagids = []
for tag in tags:
termid = getTerm(dbconn,tag)
if termid:
print tag, 'tag id is ',termid
tagids.extend(termid)
else:
termid = addTerm(dbconn,tag)
print 'add tag',tag,'id is ' ,termid
tagids.append(termid)
print 'tag id is ',tagids
直接可以执行,在第for循环里第二次调用getTerm函数时,报错如下:
Traceback (most recent call last):
File "a.py", line 40, in <module>
termid = getTerm(dbconn,tag)
File "a.py", line 11, in getTerm
count = cursor.execute(query,tag)
File "/usr/lib64/python2.6/site-packages/MySQLdb/cursors.py", line 154, in execute
charset = db.character_set_name()
_mysql_exceptions.InterfaceError: (0, '')
二、解决方法
初始时以为是编码问题了,又细核对了几遍未发现编码有问题,在python代码里也未发现异常。后来问过师傅后,师傅来了句提示:
只看代码有啥用,mysql 的超时时间调长点或捕获异常从连,原因是
cursor. connection 没有关闭
但是socket已经断了
cursor 这个行为不会再建立一次socket的
重新执行一次MysqlDB.connect()
看的有点懵懂,先从mysql 里查看了所有timeout相关的变量
?
1
mysql> show GLOBAL VARIABLES like "%timeout%";
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| connect_timeout | 10 |
| delayed_insert_timeout | 300 |
| innodb_lock_wait_timeout | 50 |
| innodb_rollback_on_timeout | OFF |
| interactive_timeout | 28800 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| slave_net_timeout | 3600 |
| table_lock_wait_timeout | 50 |
| wait_timeout | 28800 |
+----------------------------+-------+
10 rows in set (0.00 sec)
发现最小的超时时间是10s ,而我的程序执行起来显然就不了10s 。因为之前查过相关的报错,这里估计这个很可能是另外一个报错:2006,MySQL server has gone away 。即然和这个超时时间应该没关系,那就尝试通过MySQLdb ping测试,如果捕获异常,就再进行重连,修改后的代码为:
#!/usr/bin/python
#coding=utf-8
import MySQLdb
def getTerm(db,tag):
cursor = db.cursor()
query = "SELECT term_id FROM wp_terms where name=%s "
count = cursor.execute(query,tag)
rows = cursor.fetchall()
db.commit()
#db.close()
if count:
term_id = [int(rows[id][0]) for id in range(count)]
print term_id
return term_id
else:return None
def addTerm(db,tag):
cursor = db.cursor()
query = "INSERT into wp_terms (name,slug,term_group) values (%s,%s,0)"
data = (tag,tag)
cursor.execute(query,data)
db.commit()
term_id = cursor.lastrowid
sql = "INSERT into wp_term_taxonomy (term_id,taxonomy,description) values (%s,'post_tag',%s) "
value = (term_id,tag)
cursor.execute(sql,value)
db.commit()
db.close()
return int(term_id)
dbconn = MySQLdb.connect(host='localhost', user='root', passwd='123456', db='361way', port=3306, charset='utf8', init_command='set names utf8')
tags = ['mysql','1111','aaaa','bbbb','ccccc','php','abc','python','java']
if __name__ == "__main__":
tagids = []
for tag in tags:
try:
dbconn.ping()
except:
print 'mysql connect have been close'
dbconn = MySQLdb.connect(host='localhost', user='root', passwd='123456', db='361way', port=3306, charset='utf8', init_command='set names utf8')
termid = getTerm(dbconn,tag)
if termid:
print tag, 'tag id is ',termid
tagids.extend(termid)
else:
termid = addTerm(dbconn,tag)
print 'add tag',tag,'id is ' ,termid
tagids.append(termid)
print 'All tags id is ',tagids
再执行发现竟然OK了,而细看下结果,发现基本上每1-2次getTerm或addTerm函数调用就会打印一次'mysql connect have been close' 。
三、使用torndb模块解决mysql断连问题
1.MySQLdb和torndb的代码样例对比
torndb是facebook开源的一个基于MySQLdb二次封装的一个mysql模块,新封装的这个模块比较小,是一个只有2百多行代码的py文件。虽然代码短,功能确相较MySQLdb简便不少,并且该模块由于增加了reconnect方法和max_idel_time参数,解决了mysql的断连问题。比较下使用原生MySQLdb模块和使用torndb模块的代码:
使用MySQLdb模块的代码
import MySQLdb
def getTerm(db,tag):
cursor = db.cursor()
query = "SELECT term_id FROM wp_terms where name=%s "
count = cursor.execute(query,tag)
rows = cursor.fetchall()
db.commit()
#db.close()
if count:
term_id = [int(rows[id][0]) for id in range(count)]
return term_id
else:return None
def addTerm(db,tag):
cursor = db.cursor()
query = "INSERT into wp_terms (name,slug,term_group) values (%s,%s,0)"
data = (tag,tag)
cursor.execute(query,data)
db.commit()
term_id = cursor.lastrowid
sql = "INSERT into wp_term_taxonomy (term_id,taxonomy,description) values (%s,'post_tag',%s) "
value = (term_id,tag)
cursor.execute(sql,value)
db.commit()
db.close()
return int(term_id)
def addCTag(db,data):
cursor = db.cursor()
query = '''INSERT INTO `wp_term_relationships` (
`object_id` ,
`term_taxonomy_id`
)
VALUES (
%s, %s) '''
cursor.executemany(query,data)
db.commit()
db.close()
dbconn = MySQLdb.connect(host='localhost', user='root', passwd='123456', db='361way', port=3306, charset='utf8', init_command='set names utf8')
tags = ['mysql','1111','aaaa','bbbb','ccccc','php','abc','python','java']
tagids = []
for tag in tags:
if termid:
try:
dbconn.ping()
except:
dbconn = MySQLdb.connect(host='localhost', user='root', passwd='123456', db='361way', port=3306, charset='utf8', init_command='set names utf8')
print tag, 'tag id is ',termid
termid = getTerm(dbconn,tag)
tagids.extend(termid)
else:
try:
dbconn.ping()
except:
dbconn = MySQLdb.connect(host='localhost', user='root', passwd='123456', db='361way', port=3306, charset='utf8', init_command='set names utf8')
termid = addTerm(dbconn,tag)
print 'add tag',tag,'id is ' ,termid
tagids.append(termid)
print 'tag id is ',tagids
postid = '35'
tagids = list(set(tagids))
ctagdata = []
for tagid in tagids:
ctagdata.append((postid,tagid))
try:
dbconn.ping()
except:
dbconn = MySQLdb.connect(host='localhost', user='root', passwd='123456', db='361way', port=3306, charset='utf8', init_command='set names utf8')
addCTag(dbconn,ctagdata)
使用torndb的代码
#!/usr/bin/python
#coding=utf-8
import torndb
def getTerm(db,tag):
query = "SELECT term_id FROM wp_terms where name=%s "
rows = db.query(query,tag)
termid = []
for row in rows:
termid.extend(row.values())
return termid
def addTerm(db,tag):
query = "INSERT into wp_terms (name,slug,term_group) values (%s,%s,0)"
term_id = db.execute_lastrowid(query,tag,tag)
sql = "INSERT into wp_term_taxonomy (term_id,taxonomy,description) values (%s,'post_tag',%s) "
db.execute(sql,term_id,tag)
return term_id
def addCTag(db,data):
query = "INSERT INTO wp_term_relationships (object_id,term_taxonomy_id) VALUES (%s, %s) "
db.executemany(query,data)
dbconn = torndb.Connection('localhost:3306','361way',user='root',password='123456')
tags = ['mysql','1111','aaaa','bbbb','ccccc','php','abc','python','java']
tagids = []
for tag in tags:
termid = getTerm(dbconn,tag)
if termid:
print tag, 'tag id is ',termid
tagids.extend(termid)
else:
termid = addTerm(dbconn,tag)
print 'add tag',tag,'id is ' ,termid
tagids.append(termid)
print 'All tags id is ',tagids
postid = '35'
tagids = list(set(tagids))
ctagdata = []
for tagid in tagids:
ctagdata.append((postid,tagid))
addCTag(dbconn,ctagdata)
从两者的代码上来看,使用torndb模块和原生相比,发现可以省略如下两部分:
torndb模块不需要db.cursor进行处理,无不需要db.comment提交,torndb是自动提交的;
torndb不需要在每次调用时,进行db.ping()判断数据库socket连接是否断开,因为torndb增加了reconnect方法,支持自动重连。
2.torndb的方法
torndb提供的参数和方法有:
execute 执行语句不需要返回值的操作。
execute_lastrowid 执行后获得表id,一般用于插入后获取返回值。
executemany 可以执行批量插入。返回值为第一次请求的表id。
executemany_rowcount 批量执行。返回值为第一次请求的表id。
get 执行后获取一行数据,返回dict。
iter 执行查询后,返回迭代的字段和数据。
query 执行后获取多行数据,返回是List。
close 关闭
max_idle_time 最大连接时间
reconnect 关闭后再连接
使用示例:
mysql> CREATE TABLE `ceshi` (`id` int(1) NULL AUTO_INCREMENT ,`num` int(1) NULL ,PRIMARY KEY (`id`));
>>> import torndb
>>> db = torndb.Connection("127.0.0.1","数据库名","用户名", "密码", 24*3600) # 24*3600为超时时间
>>> get_id1 = db.execute_lastrowid("insert ceshi(num) values('1')")
>>> print get_id1
1
>>> args1 = [('2'),('3'),('4')]
>>> get1 = db.executemany("insert ceshi(num) values(%s)", args1)
>>> print get1
2
>>> rows = db.iter("select * from ceshi")
>>> for i in rows:
… print i
3.报错
在使用过程中可能遇到的错误:
File "/home/361way/database.py", line 145, in execute_lastrowid
self._execute(cursor, query, parameters)
File "/home/361way/database.py", line 207, in _execute
return cursor.execute(query, parameters)
File "/usr/lib/pymodules/python2.7/MySQLdb/cursors.py", line 159, in execute
query = query % db.literal(args)
TypeError: not enough arguments for format string
写上面的代码时,我刚开始还是试着使用MySQLdb模块的方式引用数据,结果发现报参数的错误 ,经查看代码发现 ,torndb在使用几个sql方法时较MySQLdb精简过了。具体各个方法的传参方法如下(注意参数个数):
close()
reconnect()
iter(query, *parameters, **kwparameters)
query(query, *parameters, **kwparameters)
get(query, *parameters, **kwparameters)
execute(query, *parameters, **kwparameters)
execute_lastrowid(query, *parameters, **kwparameters)
execute_rowcount(query, *parameters, **kwparameters)
executemany(query, parameters)
executemany_lastrowid(query, parameters)
executemany_rowcount(query, parameters)
update(query, *parameters, **kwparameters)
updatemany(query, parameters)
insert(query, *parameters, **kwparameters)
insertmany(query, parameters)
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
【核心关键词】大数据、零售商、消费者、供应链、运营、企业、产品、客户、数据模型、大数据平台、数据开发、系统运维、业务逻 ...
2026-06-26在物流配送、供应链履约、终端供货等业务场景中,送货率是衡量企业履约能力、服务质量、供应链稳定性的核心业务指标,直接关联客 ...
2026-06-26 很多数据分析师精通描述性统计,能熟练计算均值、中位数、标准差,但当被问到“用500个样本如何推断10万用户的真实满意度” ...
2026-06-26在数字化管理与数据化运营体系中,指标是连接原始数据与业务决策的核心载体。零散的原始数据只是无意义的数值堆砌,无法直接反映 ...
2026-06-25在Excel数据汇总、财务统计、业务复盘等日常办公场景中,经常需要完成逐行相乘、整体汇总求和的计算需求,最典型的场景就是:单 ...
2026-06-25 很多数据分析师沉迷于复杂的机器学习算法,却忽略了数据分析最基础也最核心的能力——描述性统计。事实上,80%的商业分析问 ...
2026-06-25【核心关键词】主数据、资产、供应商、现金流、企业、精细化、集团、数字化、中国、数据质量、数据管理、经营管理、地产行业、 ...
2026-06-24在数据分析、假设检验、AB测试、学术研究等统计场景中,显著水平(α)与P值(P-value)是判断统计结果是否具有统计学意义的两个 ...
2026-06-24小李刚入职了一家互联网公司的运营部门。第一次参加业务复盘会,运营主管问了一个看似简单的问题:“这个月新用户留存率下降了5 ...
2026-06-24在数字化转型全面渗透的产业背景下,数据分析已成为互联网、金融、零售、制造等几乎所有行业的核心岗位能力。很多初学者对数据分 ...
2026-06-23在企业并购、股权定价、投融资评估、资产核算等资本市场核心场景中,市场法是应用最广泛、市场认可度最高的企业价值评估方法。传 ...
2026-06-23 许多数据分析师精通Excel函数和SQL查询,但当面对一张上万行的销售明细表,要快速回答“哪个地区销量最高”“哪款产品增长最 ...
2026-06-23【核心关键词】运营、证书、金融、客户、产品、软件、销售额、量化、科技、数据分析、金融行业、证券类软件、业务流程、金融机 ...
2026-06-22在企业方案选型、产品迭代评审、供应商筛选、运营效果复盘等决策场景中,单一指标的优劣判断往往无法支撑科学决策。一套转化效果 ...
2026-06-22 很多数据分析师掌握了Excel函数、会写SQL查询,但当被问到“数据从哪里来”“数据加工有哪些步骤”“如何使用分析工具连接数 ...
2026-06-22【核心关键词】软件、洞察力、大数据、产品、经验、硬件、流量、创新、决策、数据安全、网络安全、数据分析、决策制定、数据挖 ...
2026-06-18在方案选型、效果复盘、产品评估、供应商筛选等各类业务决策场景中,仅凭单一指标下结论往往会陷入 “以偏概全” 的误区。多维度 ...
2026-06-18 很多数据分析师精通Excel单元格操作,但当被问到“表结构数据的基本处理单位是什么”“字段和记录的本质区别”“为什么表结 ...
2026-06-18在数据分析、用户运营与业务增长的工作体系中,漏斗拆解是最基础也最高频的问题定位方法。很多业务场景下,我们只能看到最终的转 ...
2026-06-17在数据库开发、数据清洗与报表统计场景中,数值类型转换为日期是高频刚需操作。业务系统常以 Unix 时间戳、整型日期(如20240617 ...
2026-06-17