2011-12-31 24 views
12

He escrito un código en PHP que devuelve el contenido html de los dominios .edu. Aquí se ofrece una breve introducción: Errors regarding Web Crawler in PHPSolución de errores del "servidor MySQL se ha ido"

El rastreador funciona bien cuando el número de enlaces para rastrear es pequeño (alrededor de 40 URL) pero me aparece el error "El servidor MySQL se ha ido" después de este número.

Estoy almacenando contenido html como texto largo en tablas MySQL y no entiendo por qué el error llega después de al menos 40-50 inserciones.

Cualquier ayuda en este sentido es muy apreciada.

Tenga en cuenta que ya he modificado wait_timeout y max_allowed_packet para acomodar mis consultas y el código php y ahora no sé qué hacer. Por favor, ayúdame en este sentido.

Respuesta

10

Usted podría estar inclinado para manejar este problema "ping" al servidor MySQL antes de una consulta. Esta es una mala idea. Para obtener más información sobre por qué, consulte esta publicación de SO: Should I ping mysql server before each query?

La mejor manera de manejar el problema es envolviendo las consultas dentro de los bloques try/catch y capturando las excepciones de la base de datos para que pueda manejarlas adecuadamente. Esto es especialmente importante en secuencias de comandos de tipo ejecución larga y/o tipo daemon. Por lo tanto, aquí hay un ejemplo muy básico utilizando un "administrador de conexión" para controlar el acceso a las conexiones de base de datos:

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

¿Ya está DbException en php? – Rafay

+2

No, esta es una clase de Excepción que usted mismo especificaría y arrojaría desde el interior de la función 'saveData()'. Actualicé la función 'saveData' y agregué una clase DbException personalizada en mi respuesta para reflejar esto ... – rdlowrey

3

Tengo another answer que trata con lo que creo que es un problema similar, y requeriría una respuesta similar. Básicamente, puede usar la función mysql_ping() para probar la conexión antes de su inserción. Antes de MySQL 5.0.14, mysql_ping() se volvería a conectar automáticamente el servidor, pero ahora tiene que crear su propia lógica de reconexión. Algo similar a esto debería funcionar para usted:

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

Hacer ping no es una buena estrategia en este caso ... para obtener más información sobre por qué, consulte esta publicación SO: [¿Debo hacer ping al servidor mysql antes de cada consulta?] (Http: // stackoverflow.com/questions/3103969/should-i-ping-mysql-server-before-each-query) – rdlowrey

0

¿Está la apertura de una sola conexión de base de datos y volver a utilizarlo? ¿Es posible que sea un tiempo de espera simple? Puede que le sea más útil abriendo una nueva conexión de base de datos para cada una de sus operaciones de lectura/escritura (contacto de IE .edu, obtener texto, abrir base de datos, escribir texto, cerrar db, repetir).

¿Cómo está utilizando el asa? ¿Es posible que haya dado un error y se haya "ido" por esa razón?

+0

¿Debo abrir una nueva conexión para cada consulta y luego cerrarla después de ejecutar esa consulta? Y repita el procedimiento para todas las consultas? – Rafay

+4

Para el registro, abrir una nueva conexión para cada consulta es terriblemente ineficiente ... – rdlowrey

+0

Vale la pena agregar que si un hilo se mata en el archivo db (con 'KILL [thread id]'), entonces obtendrá el "servidor tiene ido "error también. –

0

Bueno, esto es lo que estoy haciendo ahora en base a la sugerencia de rdlowrey y supongo que esto también es correcto.

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); 
     } 
    } 
} 

Una vez que la consulta no se ha podido ejecutar, el script se saltará pero se asegurará de que la conexión se restablezca.

Sin embargo, mi rastreador web se cuelga cuando se encuentran archivos como .jpg, .bmp, .pdf, etc. ¿Hay alguna manera de omitir esas URL que contienen estas extensiones? Estoy usando preg_match y he dado pdf y doc para que coincida. Sin embargo, quiero que la función omita todos los enlaces que contengan extensiones como mp3, pdf, etc. ¿Es esto posible?

+0

Si su conexión de db se está cerrando, sería por 1 de 2 razones: 1) su código lo está cerrando. 2) Su sistema tiene un problema importante. Nunca he visto utilizar esta estrategia de reconexión ya que nunca he visto una situación en la que se requiera. En lugar de volver a conectar en su bloque catch, intente registrar los detalles de la excepción y depurar el problema desde allí. –

2

Estaba frente a "El servidor de Mysql se ha ido" error al utilizar Mysql connector 5.X, reemplazando dll a la última versión resuelto el problema.

Cuestiones relacionadas