如何关闭PHP和&之间的连接;访问后立即Mysql

时间:2015-06-28 18:13:10

标签: php mysql

5月wabsite遇到了max_user_connections错误 在联系网站托管服务提供商后,他们说我必须在使用mysql_close()访问数据库后立即关闭连接

我的问题是,如果我的php文件是:

,我将如何关闭连接

* /

if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
    header('Location: ../');
    exit;
}


/**
 * Indicates to the Q2A database layer that database connections are permitted fro this point forwards
 * (before this point, some plugins may not have had a chance to override some database access functions).
 */
function qa_db_allow_connect()
{
    if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

    global $qa_db_allow_connect;

    $qa_db_allow_connect=true;
}


/**
 * Connect to the Q2A database, select the right database, optionally install the $failhandler (and call it if necessary).
 * Uses mysqli as of Q2A 1.7.
 */
function qa_db_connect($failhandler=null)
{
    if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

    global $qa_db_connection, $qa_db_fail_handler, $qa_db_allow_connect;

    if (!$qa_db_allow_connect)
        qa_fatal_error('It appears that a plugin is trying to access the database, but this is not allowed until Q2A initialization is complete.');

    if (isset($failhandler))
        $qa_db_fail_handler = $failhandler; // set this even if connection already opened

    if ($qa_db_connection instanceof mysqli)
        return;

    // in mysqli we connect and select database in constructor
    if (QA_PERSISTENT_CONN_DB)
        $db = new mysqli('p:'.QA_FINAL_MYSQL_HOSTNAME, QA_FINAL_MYSQL_USERNAME, QA_FINAL_MYSQL_PASSWORD, QA_FINAL_MYSQL_DATABASE);
    else
        $db = new mysqli(QA_FINAL_MYSQL_HOSTNAME, QA_FINAL_MYSQL_USERNAME, QA_FINAL_MYSQL_PASSWORD, QA_FINAL_MYSQL_DATABASE);

    // must use procedural `mysqli_connect_error` here prior to 5.2.9
    $conn_error = mysqli_connect_error();
    if ($conn_error)
        qa_db_fail_error('connect', $db->connect_errno, $conn_error);

    // From Q2A 1.5, we explicitly set the character encoding of the MySQL connection, instead of using lots of "SELECT BINARY col"-style queries.
    // Testing showed that overhead is minimal, so this seems worth trading off against the benefit of more straightforward queries, especially
    // for plugin developers.
    if (!$db->set_charset('utf8'))
        qa_db_fail_error('set_charset', $db->errno, $db->error);

    qa_report_process_stage('db_connected');

    $qa_db_connection=$db;
}


/**
 * If a DB error occurs, call the installed fail handler (if any) otherwise report error and exit immediately.
 */
function qa_db_fail_error($type, $errno=null, $error=null, $query=null)
{
    if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

    global $qa_db_fail_handler;

    @error_log('PHP Question2Answer MySQL '.$type.' error '.$errno.': '.$error.(isset($query) ? (' - Query: '.$query) : ''));

    if (function_exists($qa_db_fail_handler))
        $qa_db_fail_handler($type, $errno, $error, $query);

    else {
        echo '<hr><font color="red">Database '.htmlspecialchars($type.' error '.$errno).'<p>'.nl2br(htmlspecialchars($error."\n\n".$query));
        qa_exit('error');
    }
}


/**
 * Return the current connection to the Q2A database, connecting if necessary and $connect is true.
 */
function qa_db_connection($connect=true)
{
    if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

    global $qa_db_connection;

    if ($connect && !($qa_db_connection instanceof mysqli)) {
        qa_db_connect();

        if (!($qa_db_connection instanceof mysqli))
            qa_fatal_error('Failed to connect to database');
    }

    return $qa_db_connection;
}


/**
 * Disconnect from the Q2A database.
 */
function qa_db_disconnect()
{
    if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

    global $qa_db_connection;

    if ($qa_db_connection instanceof mysqli) {
        qa_report_process_stage('db_disconnect');

        if (!QA_PERSISTENT_CONN_DB) {
            if (!$qa_db_connection->close())
                qa_fatal_error('Database disconnect failed');
        }

        $qa_db_connection=null;
    }
}


/**
 * Run the raw $query, call the global failure handler if necessary, otherwise return the result resource.
 * If appropriate, also track the resources used by database queries, and the queries themselves, for performance debugging.
 */
function qa_db_query_raw($query)
{
    if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

    if (QA_DEBUG_PERFORMANCE) {
        global $qa_usage;

        // time the query
        $oldtime = array_sum(explode(' ', microtime()));
        $result = qa_db_query_execute($query);
        $usedtime = array_sum(explode(' ', microtime())) - $oldtime;

        // fetch counts
        $gotrows = $gotcolumns = null;
        if ($result instanceof mysqli_result) {
            $gotrows = $result->num_rows;
            $gotcolumns = $result->field_count;
        }

        $qa_usage->logDatabaseQuery($query, $usedtime, $gotrows, $gotcolumns);
    }
    else
        $result = qa_db_query_execute($query);

//  @error_log('Question2Answer MySQL query: '.$query);

    if ($result === false) {
        $db = qa_db_connection();
        qa_db_fail_error('query', $db->errno, $db->error, $query);
    }

    return $result;
}


/**
 * Lower-level function to execute a query, which automatically retries if there is a MySQL deadlock error.
 */
function qa_db_query_execute($query)
{
    if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

    $db = qa_db_connection();

    for ($attempt = 0; $attempt < 100; $attempt++) {
        $result = $db->query($query);

        if ($result === false && $db->errno == 1213)
            usleep(10000); // deal with InnoDB deadlock errors by waiting 0.01s then retrying
        else
            break;
    }

    return $result;
}


/**
 * Return $string escaped for use in queries to the Q2A database (to which a connection must have been made).
 */
function qa_db_escape_string($string)
{
    if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

    $db = qa_db_connection();
    return $db->real_escape_string($string);
}


/**
 * Return $argument escaped for MySQL. Add quotes around it if $alwaysquote is true or it's not numeric.
 * If $argument is an array, return a comma-separated list of escaped elements, with or without $arraybrackets.
 */
function qa_db_argument_to_mysql($argument, $alwaysquote, $arraybrackets=false)
{
    if (is_array($argument)) {
        $parts=array();

        foreach ($argument as $subargument)
            $parts[] = qa_db_argument_to_mysql($subargument, $alwaysquote, true);

        if ($arraybrackets)
            $result = '('.implode(',', $parts).')';
        else
            $result = implode(',', $parts);

    }
    elseif (isset($argument)) {
        if ($alwaysquote || !is_numeric($argument))
            $result = "'".qa_db_escape_string($argument)."'";
        else
            $result = qa_db_escape_string($argument);
    }
    else
        $result = 'NULL';

    return $result;
}


/**
 * Return the full name (with prefix) of database table $rawname, usually if it used after a ^ symbol.
 */
function qa_db_add_table_prefix($rawname)
{
    if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

    $prefix = QA_MYSQL_TABLE_PREFIX;

    if (defined('QA_MYSQL_USERS_PREFIX')) {
        switch (strtolower($rawname)) {
            case 'users':
            case 'userlogins':
            case 'userprofile':
            case 'userfields':
            case 'messages':
            case 'cookies':
            case 'blobs':
            case 'cache':
            case 'userlogins_ibfk_1': // also special cases for constraint names
            case 'userprofile_ibfk_1':
                $prefix = QA_MYSQL_USERS_PREFIX;
                break;
        }
    }

    return $prefix.$rawname;
}


/**
 * Callback function to add table prefixes, as used in qa_db_apply_sub().
 */
function qa_db_prefix_callback($matches)
{
    return qa_db_add_table_prefix($matches[1]);
}


/**
 * Substitute ^, $ and # symbols in $query. ^ symbols are replaced with the table prefix set in qa-config.php.
 * $ and # symbols are replaced in order by the corresponding element in $arguments (if the element is an array,
 * it is converted recursively into comma-separated list). Each element in $arguments is escaped.
 * $ is replaced by the argument in quotes (even if it's a number), # only adds quotes if the argument is non-numeric.
 * It's important to use $ when matching a textual column since MySQL won't use indexes to compare text against numbers.
 */
function qa_db_apply_sub($query, $arguments)
{
    $query = preg_replace_callback('/\^([A-Za-z_0-9]+)/', 'qa_db_prefix_callback', $query);

    if (!is_array($arguments))
        return $query;

    $countargs = count($arguments);
    $offset = 0;

    for ($argument = 0; $argument < $countargs; $argument++) {
        $stringpos = strpos($query, '$', $offset);
        $numberpos = strpos($query, '#', $offset);

        if ($stringpos === false || ($numberpos !== false && $numberpos < $stringpos)) {
            $alwaysquote = false;
            $position = $numberpos;
        }
        else {
            $alwaysquote = true;
            $position = $stringpos;
        }

        if (!is_numeric($position))
            qa_fatal_error('Insufficient parameters in query: '.$query);

        $value = qa_db_argument_to_mysql($arguments[$argument], $alwaysquote);
        $query = substr_replace($query, $value, $position, 1);
        $offset = $position + strlen($value); // allows inserting strings which contain #/$ character
    }

    return $query;
}


/**
 * Run $query after substituting ^, # and $ symbols, and return the result resource (or call fail handler).
 */
function qa_db_query_sub($query) // arguments for substitution retrieved using func_get_args()
{
    $funcargs=func_get_args();

    return qa_db_query_raw(qa_db_apply_sub($query, array_slice($funcargs, 1)));
}


/**
 * Return the number of rows in $result. (Simple wrapper for mysqli_result::num_rows.)
 */
function qa_db_num_rows($result)
{
    if ($result instanceof mysqli_result)
        return $result->num_rows;

    return 0;
}


/**
 * Return the value of the auto-increment column for the last inserted row.
 */
function qa_db_last_insert_id()
{
    $db = qa_db_connection();
    return $db->insert_id;
}


/**
 * Return the number of rows affected by the last query.
 */
function qa_db_affected_rows()
{
    $db = qa_db_connection();
    return $db->affected_rows;
}


/**
 * For the previous INSERT ... ON DUPLICATE KEY UPDATE query, return whether an insert operation took place.
 */
function qa_db_insert_on_duplicate_inserted()
{
    return (qa_db_affected_rows() == 1);
}


/**
 * Return a random integer (as a string) for use in a BIGINT column.
 * Actual limit is 18,446,744,073,709,551,615 - we aim for 18,446,743,999,999,999,999.
 */
function qa_db_random_bigint()
{
    return sprintf('%d%06d%06d', mt_rand(1, 18446743), mt_rand(0, 999999), mt_rand(0, 999999));
}


/**
 * Return an array of the names of all tables in the Q2A database, converted to lower case.
 * No longer used by Q2A and shouldn't be needed.
 */
function qa_db_list_tables_lc()
{
    return array_map('strtolower', qa_db_list_tables());
}


/**
 * Return an array of the names of all tables in the Q2A database.
 */
function qa_db_list_tables()
{
    return qa_db_read_all_values(qa_db_query_raw('SHOW TABLES'));
}

/ *     choicespec数组可以包含以下元素。有关大量示例,请参阅qa-db-choices.php。

1 个答案:

答案 0 :(得分:2)

我敢打赌你的代码设置为使用MySQL的持久连接。这可能导致开放但空闲的连接,最大化您(最可能共享)的托管服务提供商为您分配的任何内容。

您的代码中有QA_PERSISTENT_CONN_DB常量,用于确定您的连接模式。您会发现它在配置文件中的某处定义为truefalse。 (它没有在上面的代码中定义)。确保将其设置为false并查看问题是否已解决。当持久连接关闭时,上面的代码负责关闭连接。您无需添加它。

如果您有兴趣了解有关持久连接的更多信息,this answer涵盖了很多内容; manual中还有更多内容:

  

持久连接是在脚本执行结束时不关闭的链接。

下次,请务必仔细阅读您的代码以了解功能是否已经存在(在这种情况下,它位于function qa_db_disconnect()内),如果仅仅是配置问题。