Python中MySQLdb和torndb模块对MySQL的断连问题处理

作者:goldensun 时间:2024-01-29 02:05:25 

在使用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相关的变量


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)
标签:Python,MySQL
0
投稿

猜你喜欢

  • 详解Python中pyautogui库的最全使用方法

    2022-11-17 17:07:14
  • jQuery实现弹出带遮罩层的居中浮动窗口效果

    2024-04-19 10:17:20
  • ML神器:sklearn的快速使用及入门

    2023-04-17 04:42:09
  • 用 JavaScript 解数学题

    2010-07-09 13:38:00
  • 详解Go多协程并发环境下的错误处理

    2024-02-15 21:11:59
  • php返回相对时间(如:20分钟前,3天前)的方法

    2023-10-26 11:20:38
  • 阿里云安装mysql数据库出现2002错误解决办法

    2024-01-15 10:59:14
  • 基于Linux系统中python matplotlib画图的中文显示问题的解决方法

    2022-05-22 01:34:28
  • Pandas操作CSV文件的读写实现方法

    2022-05-12 09:48:05
  • mysql 索引合并的使用

    2024-01-14 05:53:39
  • go语言map字典删除操作的方法

    2024-02-03 16:19:37
  • 关于Python中的向量相加和numpy中的向量相加效率对比

    2022-09-30 04:22:44
  • 简明 Python 基础学习教程

    2023-01-05 13:02:05
  • 在SQL Server中使用索引的技巧

    2009-02-24 17:50:00
  • 详解Python 3D引擎Ursina如何绘制立体图形

    2021-11-17 06:04:20
  • vue中自定义指令directive的详细指南

    2024-05-28 15:46:48
  • TorchVision Transforms API目标检测实例语义分割视频类

    2022-12-05 14:24:56
  • SQL Server 2008打开输入sa密码提示无法登陆数据库的解决方法

    2024-01-29 09:39:04
  • 总结Python连接CS2000的详细步骤

    2023-04-21 20:26:33
  • 对python中xlsx,csv以及json文件的相互转化方法详解

    2021-01-28 23:24:34
  • asp之家 网络编程 m.aspxhome.com