python多线程爬虫往mysql里面写数据导致死锁
PHP中文网
PHP中文网 2017-04-18 10:10:53
0
3
438

我在爬虫里面用的是MySQLdb这个包进行insert操作,我一开始是所有子线程公用一个mysql连接,结果发现数据写不进去,然后我又试过所有子线程公用一个cursor游标,出现了只有部分数据写进去了,而且自增id居然还自增了。(也就是数据没有写入进去,但是自增id的自增数增加了),最后我干脆每个子线程在每一次写入的时候创建一个连接句柄,然后就出现了如图症状,请问这该怎么办啊?有什么优化方法吗?

PHP中文网
PHP中文网

认证高级PHP讲师

全部回覆(3)
刘奇

謝邀。 Metadata Lock(MDL)是在5.5才引進到mysql的元資料保護機制。 5.5對於metadata的保護是事務層級的,只有在事務結束後才釋放MDL。
當一個會話在主庫執行DML 操作還沒提交時,另一個會話對同一個物件執行了DDL 操作如drop table,而由於MySQL 的binlog 是基於事務提交的先後順序進行記錄的,因此在從庫上應用時,就出現了先drop table,然後再向table 中insert 的情況,導致從庫應用出錯。 因此,MySQL 在 5.5.3 版本後引入了 Metadata lock,只有在事務結束後才會釋放 Metadata lock,因此在事務提交或回滾前,是無法進行 DDL 操作的。
造成Waiting for table metadata lock的原因,一般是以下幾個簡單的場景:
場景一:長事物運行,阻塞DDL,繼而阻塞所有同表的後續操作
場景二:未提交事物,阻塞DDL,繼而阻塞所有同表的後續操作

那麼如何解決呢?
查看所有的處於等待阻塞狀態的事務鎖定lock

USE INFORMATION_SCHEMA
SELECT * 
FROM INNODB_LOCKS 
WHERE LOCK_TRX_ID IN (SELECT BLOCKING_TRX_ID FROM INNODB_LOCK_WAITS);

或是你可以直接定位到特定表

SELECT * FROM INNODB_LOCKS 
WHERE LOCK_TABLE = db_name.table_name;

直接刪除相關記錄應該是可以解除鎖定。

建議:採用連接池而不是所有執行緒公用一個連接,每個事務都記得提交或回滾等。
建議參考:
https://dev.mysql.com/doc/ref...
http://www.cnblogs.com/cchust...
https://gold.xitu.io/entry/57 ...
http://www.cnblogs.com/digdee...

Peter_Zhu

表是 Innodb 的吧,然後沒開自動提交也沒有手動提交。

黄舟

首先,多執行緒共用一個連接,相當於並發,很多執行緒需要等待。
每個執行緒一個連線利用率不高,所以一般都是連線池。不用了回收,並且連接一直保持,避免了頻繁連接斷開。

配圖,題主是否開啟事務

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板