2011-12-31 16 views
12

Ho scritto del codice in PHP che restituisce il contenuto html dai domini .edu. Una breve introduzione è dato qui: Errors regarding Web Crawler in PHPRisoluzione degli errori "Il server MySQL è andato via"

Il crawler funziona bene quando il numero di link da sottoporre a scansione sono piccole (qualcosa di circa 40 URL), ma io sono sempre "server MySQL è andato via" errore dopo questo numero.

Sto memorizzando il contenuto html come longtext nelle tabelle MySQL e non capisco perché l'errore arriva dopo almeno 40-50 inserimenti.

Qualsiasi aiuto in questo senso è molto apprezzato.

Si prega di notare che ho già modificato il wait_timeout e il max_allowed_packet per soddisfare le mie richieste e il codice php e ora non so cosa fare. Per favore aiutami in questo senso.

risposta

10

Si potrebbe essere incline a gestire questo problema "ping" del server MySQL prima di una query. Questa è una cattiva idea. Per ulteriori informazioni sul motivo, controllare questo post in SO: Should I ping mysql server before each query?

Il modo migliore per gestire il problema è racchiudere le query all'interno dei blocchi try/catch e rilevare eventuali eccezioni del database in modo che sia possibile gestirle in modo appropriato. Questo è particolarmente importante negli script di tipo long run e/o daemon. Quindi, ecco un esempio molto semplice utilizzando una "connection manager" per controllare l'accesso alle connessioni DB:

class DbPool { 

    private $connections = array(); 

    function addConnection($id, $dsn) { 
     $this->connections[$id] = array(
      'dsn' => $dsn, 
      'conn' => null 
     ); 
    } 

    function getConnection($id) { 
     if (!isset($this->connections[$id])) { 
      throw new Exception('Invalid DB connection requested'); 
     } elseif (isset($this->connections[$id]['conn'])) { 
      return $this->connections[$id]['conn']; 
     } else { 
      try { 
       // for mysql you need to supply user/pass as well 
       $conn = new PDO($dsn); 

       // Tell PDO to throw an exception on error 
       // (like "MySQL server has gone away") 
       $conn->setAttribute(
        PDO::ATTR_ERRMODE, 
        PDO::ERRMODE_EXCEPTION 
       ); 
       $this->connections[$id]['conn'] = $conn; 

       return $conn; 
      } catch (PDOException $e) { 
       return false; 
      } 
     } 
    } 

    function close($id) { 
     if (!isset($this->connections[$id])) { 
      throw new Exception('Invalid DB connection requested'); 
     } 
     $this->connections[$id]['conn'] = null; 
    } 


} 


class Crawler { 

    private $dbPool; 

    function __construct(DbPool $dbPool) { 
     $this->dbPool = $dbPool; 
    } 

    function crawl() { 
     // craw and store data in $crawledData variable 
     $this->save($crawledData); 
    } 

    function saveData($crawledData) { 
     if (!$conn = $this->dbPool->getConnection('write_conn') { 
      // doh! couldn't retrieve DB connection ... handle it 
     } else { 
      try { 
       // perform query on the $conn database connection 
      } catch (Exception $e) { 
       $msg = $e->getMessage(); 
       if (strstr($msg, 'MySQL server has gone away') { 
        $this->dbPool->close('write_conn'); 
        $this->saveData($val); 
       } else { 
        // some other error occurred 
       } 
      } 
     } 
    } 
} 
+0

È già presente DbException in php ?? – Rafay

+2

No, questa è una classe Exception che specifichi tu stesso e che passi dalla funzione 'saveData()'. Ho aggiornato la funzione 'saveData' e ho aggiunto una classe personalizzata DbException nella mia risposta per riflettere questo ... – rdlowrey

3

Ho another answer che si occupa di quello che penso sia un problema simile e richiederebbe una risposta simile. Fondamentalmente, è possibile utilizzare la funzione mysql_ping() per testare la connessione prima dell'inserto. Prima di MySQL 5.0.14, mysql_ping() riconnetteva automaticamente il server, ma ora è necessario creare la propria logica di riconnessione. Qualcosa di simile a questo dovrebbe funzionare per voi:

function check_dbconn($connection) { 
    if (!mysql_ping($connection)) { 
     mysql_close($connection); 
     $connection = mysql_connect('server', 'username', 'password'); 
     mysql_select_db('db',$connection); 
    } 
    return $connection; 
} 

foreach($array as $value) { 
    $dbconn = check_dbconn($dbconn); 
    $sql="insert into collected values('".$value."')"; 
    $res=mysql_query($sql, $dbconn); 
    //then some extra code. 
} 
+1

Il ping non è una buona strategia in questo caso ... per ulteriori informazioni sul motivo, controllare questo post in SO: [Devo eseguire il ping di server mysql prima di ogni query?] (Http: // stackoverflow.it/questions/3103969/should-i-ping-mysql-server-before-each-query) – rdlowrey

0

Si sta aprendo una singola connessione DB e riutilizzarlo? È possibile che sia un timeout semplice? Si potrebbe essere meglio serviti aprendo una nuova connessione DB per ciascuna delle operazioni di lettura/scrittura (contatto IE .edu, ottenere testo, aprire DB, scrivere testo, chiudere db, ripetere).

Anche come si utilizza la maniglia? È possibile che abbia riscontrato un errore e si sia "allontanato" per questo motivo?

+0

Devo aprire una nuova connessione per ogni query e chiuderla dopo aver eseguito quella query? E ripeti la procedura per tutte le domande ?? – Rafay

+4

Per la cronaca, aprire una nuova connessione per ogni query è orribilmente inefficiente ... – rdlowrey

+0

Vale la pena aggiungere che se un thread viene ucciso sul db (con 'KILL [ID thread]'), si otterrà il "server" andato via "anche l'errore. –

0

Bene Questo è quello che sto facendo ora basato sul suggerimento di rdlowrey e immagino che anche questo sia giusto.

public function url_db_html($sourceLink = NULL, $source) { 
    $source = mysql_real_escape_string($source); 

    $query = "INSERT INTO html (id, sourceLink, sourceCode) 
      VALUES (NULL,('$sourceLink') , ('$source'))"; 

    try { 
     if(mysql_query($query, $this->connection)==FALSE) { 
      $msg = mysql_errno($this->connection) . ": " . mysql_error($this->connection); 
      throw new DbException($msg); 
     }   
    } catch (DbException $e) { 
     echo "<br><br>Catched!!!<br><br>"; 
     if(strstr($e->getMessage(), 'MySQL server has gone away')) { 
      $this->connection = mysql_connect("localhost", "root", ""); 
      mysql_select_db("crawler1", $this->connection); 
     } 
    } 
} 

Quindi, una volta che la query non è riuscita a eseguire, lo script salterà ma si assicurerà che la connessione sia ristabilita.

Tuttavia, il mio crawler Web si arresta in modo anomalo quando vengono rilevati file come .jpg, .bmp, .pdf, ecc. C'è un modo per saltare quegli URL contenenti queste estensioni. Sto usando preg_match e ho dato pdf e doc per abbinare. Eppure voglio che la funzione salti tutti i collegamenti contenenti estensioni come mp3, pdf, ecc. È possibile ??

+0

Se la tua connessione db si sta chiudendo sarebbe da 1 di 2 motivi: 1) il tuo codice lo sta chiudendo. 2) Il tuo sistema ha qualche problema importante. Non ho mai visto questa strategia di riconnessione utilizzata poiché non ho mai visto una situazione in cui dovrebbe essere richiesta. Invece di riconnettersi nel blocco catch, prova a registrare i dettagli delle eccezioni ed esegui il debug del problema da lì. –

2

Mi trovavo di fronte "Il server Mysql è andato via" errore durante l'utilizzo di Mysql connector 5.X, la sostituzione di dll per l'ultima versione ha risolto il problema.

Problemi correlati