MySQLi query results: Best approach, do you close, free, both?

后端 未结 5 1822
小蘑菇
小蘑菇 2021-01-30 07:04

I have some questions about using MySQLi, queries, and related memory management. The code here is just to clarify my questions, so don\'t dump on it for error checking, etc. I

5条回答
  •  既然无缘
    2021-01-30 07:44

    As rare as they are, in my opinion memory leaks are a nightmare to find and correct. I go out of my way to avoid them. Below is the pattern I use, based on the code you supplied:

    $db = NULL;
    try {
        $dbPool = "p:$dbhost"; // question 3: use pooling
        $db = new mysqli($dbPool, $un, $ps, $dbname);
        if ($db->connect_errno) {
            throw new Exception('' . $db->connect_error . ' ' . $db->connect_errno 
                    . "\n" . $un . '@' . $dbhost . ' ' . $dbname);
            // NOTE: It's commonly considered a security 
            // risk to output connection information e.g.
            // host, user and database names.
        }
    
        $query = "SELECT field1, field2 ".
                 "FROM table1 ".
                 "WHERE field1={$some_value}";
    
        $results = NULL;
        try {
    
            if (!$results = $db->query($query)) {
                throw new Exception($db->error . " " . $db->errno 
                        . "\n" . $query);
                // NOTE: It's commonly considered a security 
                // risk to output SQL ($query).
            }
            while ($result = $results->fetch_object()) {
                // Do something with the results
            }
    
        } catch (Exception $ex) {
            // log, report, or otherwise handle the error
        }
        if ($results) {
            $results->free(); // question 1: why risk it?
        }
    
        $query = "SELECT field1, field2 ".
                 "FROM table2 ".
                 "WHERE field1={$some_value2}";
    
        $results = NULL; 
        try {
    
            if (!$results = $db->query($query)) {
                throw new Exception($db->error . " " . $db->errno 
                        . "\n" . $query);
                // NOTE: It's commonly considered a security 
                // risk to output SQL ($query).
            }            
            while ($result = $results->fetch_object()) {
                // Do something with the second set of results
            }
    
        } catch (Exception $ex) {
            // log, report, or otherwise handle the error
        }
        if ($results) {
            $results->free(); // question 2: again, why risk it?
        }
    
    } catch (Exception $ex) {
        // log, report, or otherwise handle the error
    }
    if ($db) {
        $db->close();
    }
    

    In my opinion, connection pooling increases the chances for a memory leak, but according to the manual, the connection pooling libraries do a lot of cleanup for you automatically:

    The persistent connection of the mysqli extension however provides built-in cleanup handling code. The cleanup carried out by mysqli includes:

    Rollback active transactions

    Close and drop temporary tables

    Unlock tables

    Reset session variables

    Close prepared statements (always happens with PHP)

    Close handler

    Release locks acquired with GET_LOCK()

    This ensures that persistent connections are in a clean state on return from the connection pool, before the client process uses them.

    source: http://php.net/manual/en/mysqli.persistconns.php

    I also agree with Pascal MARTIN that it's a good idea to open your connection at the beginning of your script and close it at the end. I think connection pooling makes that less important, but still a good idea.

提交回复
热议问题