Python中MySQLdb和torndb模塊對MySQL的斷連問題處理
在使用python 對wordpress tag 進(jìn)行細(xì)化代碼處理時,遇到了調(diào)用MySQLdb模塊時的出錯,由于錯誤提示和問題原因相差甚遠(yuǎn),查看了N久代碼也未發(fā)現(xiàn)代碼有問題。后來問了下師傅,被告知MySQLdb里有一個斷接的坑 ,需要進(jìn)行數(shù)據(jù)庫重連解決。
一、報錯代碼及提示
運(yùn)行出錯的代碼如下:
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
直接可以執(zhí)行,在第for循環(huán)里第二次調(diào)用getTerm函數(shù)時,報錯如下:
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, '')
二、解決方法
初始時以為是編碼問題了,又細(xì)核對了幾遍未發(fā)現(xiàn)編碼有問題,在python代碼里也未發(fā)現(xiàn)異常。后來問過師傅后,師傅來了句提示:
只看代碼有啥用,mysql 的超時時間調(diào)長點(diǎn)或捕獲異常從連,原因是
cursor. connection 沒有關(guān)閉
但是socket已經(jīng)斷了
cursor 這個行為不會再建立一次socket的
重新執(zhí)行一次MysqlDB.connect()
看的有點(diǎn)懵懂,先從mysql 里查看了所有timeout相關(guān)的變量
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)
發(fā)現(xiàn)最小的超時時間是10s ,而我的程序執(zhí)行起來顯然就不了10s 。因為之前查過相關(guān)的報錯,這里估計這個很可能是另外一個報錯:2006,MySQL server has gone away 。即然和這個超時時間應(yīng)該沒關(guān)系,那就嘗試通過MySQLdb ping測試,如果捕獲異常,就再進(jìn)行重連,修改后的代碼為:
#!/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
再執(zhí)行發(fā)現(xiàn)竟然OK了,而細(xì)看下結(jié)果,發(fā)現(xiàn)基本上每1-2次getTerm或addTerm函數(shù)調(diào)用就會打印一次'mysql connect have been close' 。
三、使用torndb模塊解決mysql斷連問題
1.MySQLdb和torndb的代碼樣例對比
torndb是facebook開源的一個基于MySQLdb二次封裝的一個mysql模塊,新封裝的這個模塊比較小,是一個只有2百多行代碼的py文件。雖然代碼短,功能確相較MySQLdb簡便不少,并且該模塊由于增加了reconnect方法和max_idel_time參數(shù),解決了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模塊和原生相比,發(fā)現(xiàn)可以省略如下兩部分:
torndb模塊不需要db.cursor進(jìn)行處理,無不需要db.comment提交,torndb是自動提交的;
torndb不需要在每次調(diào)用時,進(jìn)行db.ping()判斷數(shù)據(jù)庫socket連接是否斷開,因為torndb增加了reconnect方法,支持自動重連。
2.torndb的方法
torndb提供的參數(shù)和方法有:
execute 執(zhí)行語句不需要返回值的操作。
execute_lastrowid 執(zhí)行后獲得表id,一般用于插入后獲取返回值。
executemany 可以執(zhí)行批量插入。返回值為第一次請求的表id。
executemany_rowcount 批量執(zhí)行。返回值為第一次請求的表id。
get 執(zhí)行后獲取一行數(shù)據(jù),返回dict。
iter 執(zhí)行查詢后,返回迭代的字段和數(shù)據(jù)。
query 執(zhí)行后獲取多行數(shù)據(jù),返回是List。
close 關(guān)閉
max_idle_time 最大連接時間
reconnect 關(guān)閉后再連接
使用示例:
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","數(shù)據(jù)庫名","用戶名", "密碼", 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
在使用過程中可能遇到的錯誤:
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模塊的方式引用數(shù)據(jù),結(jié)果發(fā)現(xiàn)報參數(shù)的錯誤 ,經(jīng)查看代碼發(fā)現(xiàn) ,torndb在使用幾個sql方法時較MySQLdb精簡過了。具體各個方法的傳參方法如下(注意參數(shù)個數(shù)):
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)
相關(guān)文章
Python ADF 單位根檢驗 如何查看結(jié)果的實現(xiàn)
這篇文章主要介紹了Python ADF 單位根檢驗 如何查看結(jié)果的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06python開發(fā)之thread線程基礎(chǔ)實例入門
這篇文章主要介紹了python開發(fā)之thread線程基礎(chǔ),以三個實例形式分析了Python中thread線程的基本使用方法,涉及串行與并行程序的執(zhí)行原理及線程的操作技巧,需要的朋友可以參考下2015-11-11