首頁  >  問答  >  主體

python多线程爬虫往mysql里面写数据导致死锁

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

PHP中文网PHP中文网2741 天前402

全部回覆(3)我來回復

  • 怪我咯

    怪我咯2017-04-18 10:12:53

    謝邀。 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...

    回覆
    0
  • 天蓬老师

    天蓬老师2017-04-18 10:12:53

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

    回覆
    0
  • 黄舟

    黄舟2017-04-18 10:12:53

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

    配圖,題主是否開啟事務

    回覆
    0
  • 取消回覆