web-dev-qa-db-ja.com

「MySQLサーバーがなくなった」エラーの解決

PHP .eduドメインからhtmlコンテンツを返すコードを書きました。ここに簡単な紹介を示します: PHPのWebクローラーに関するエラー

クロールするリンクの数が少ない(40のURL程度)場合、クローラーは正常に動作しますが、この数の後に「MySQLサーバーがなくなった」エラーが発生します。

MySQLテーブルにHTMLコンテンツをロングテキストとして保存していますが、少なくとも40〜50回の挿入後にエラーが発生する理由がわかりません。

この点で助けていただければ幸いです。

クエリとphpコードに対応するために、すでにwait_timeoutとmax_allowed_pa​​cketを変更しているため、どうすればよいかわからないことに注意してください。この点で私を助けてください。

16
Rafay

クエリの前にmysqlサーバーに「ping」することで、この問題を処理する傾向があるかもしれません。これは悪い考えです。理由の詳細については、これを確認してくださいSO post: 各クエリの前にmysqlサーバーにpingする必要がありますか?

この問題を処理する最良の方法は、try/catchブロック内でクエリをラップし、データベースの例外をキャッチして、適切に処理できるようにすることです。これは、実行時間の長いスクリプトやデーモンタイプのスクリプトで特に重要です。そこで、「接続マネージャ」を使用して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
                }
            }
        }
    }
}
14
rdlowrey

私は 別の答え を持っています。これは、私が同様の問題であると私が考えるものを扱い、同様の答えを必要とするでしょう。基本的に、挿入前に mysql_ping() 関数を使用して接続をテストできます。 MySQL 5.0.14より前は、mysql_ping()がサーバーを自動的に再接続していましたが、今度は独自の再接続ロジックを構築する必要があります。これに似たものがあなたのために働くはずです:

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.
}
4
bhamby

私が直面していたのは"Mysqlサーバーが削除されました"Mysql connector 5.Xの使用中にエラーが発生し、dllを最新バージョンに置き換えることで問題が解決しました。

1
Francois

単一のDB接続を開いて再利用していますか?単純なタイムアウトである可能性はありますか?読み取り/書き込み操作(IE連絡先.edu、テキストを取得、DBを開く、テキストを書き込む、DBを閉じる、繰り返し)ごとに新しいDB接続を開くと、サービスが向上する可能性があります。

また、ハンドルの使い方は?エラーが発生し、その理由で「なくなった」可能性はありますか?

0
ethrbunny

さて、これはrdlowreyの提案に基づいて私が現在行っていることであり、これも正しいと思います。

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

したがって、クエリの実行に失敗すると、スクリプトはそれをスキップしますが、接続が再確立されたことを確認します。

ただし、.jpg、.bmp、.pdfなどのファイルが検出されると、Webクローラーがクラッシュします。これらの拡張機能を含むURLをスキップする方法はありますか?私はpreg_matchを使用しており、一致するpdfとdocを提供しています。しかし、mp3、pdfなどの拡張子を含むすべてのリンクをスキップする機能が必要です。これは可能ですか?

0
Rafay