PHP / MySQL - 连接问题太多了

时间:2016-01-18 20:01:35

标签: php database oop model-view-controller mysqli

我正在使用OOP PHP开发CMS。这一切都运作良好,但昨天添加新功能后,它只是崩溃。现在它在访问任何页面时检索此错误:

  

警告:mysqli :: mysqli():( HY000 / 1040):连接太多   第15行上的/var/www/html/Projects/CMS4/lib/DB.php连接失败:   1040连接太多致命错误:调用成员函数   在一个非对象上的render()   第33行的/var/www/html/Projects/CMS4/controllers/BaseController.php

我可以处理致命的错误。但是,关于“太多连接”错误,我理解我正在做太多调用新的mysqli(),也许我可以通过更改mysql上的max_connections来解决它,但这是否合适?或者我在代码中做错了什么我应该改进?我怎样才能减少我的联系?这是我的DB类:

db.php中

<?php
namespace Core;

if ( !class_exists( 'DB' ) ) {

    class DB {

        private $cxn = null;

    public function __construct() {
        $this->connect();
    }

    private function connect() {
        if ( $this->cxn !== null ) {
            return;
        }
        $this->cxn = new \mysqli( DB_HOST, DB_USER, DB_PASS, DB_NAME );
        if ( $this->cxn->connect_error ) {
            die( "Connection failed: " . $this->cxn->connect_errno . ' ' . $this->cxn->connect_error );
        }
    }

        private function create_db( $name ) {
            $sql = "CREATE DATABASE IF NOT EXISTS $name";
            if( !$this->cxn->query( $sql ) ){
                die( "Error creating database: " . $this->cxn->errno . ' ' . $this->cxn->error );
            }
        }

        private function select_db( $name ) {
            if( !$this->cxn->select_db( $name ) ){
                die( "Error selecting database: " . $this->cxn->errno . ' ' . $this->cxn->error );
            }
        }

        /**
         * Create a new table in the db with the specified columns
         * @param  array $tables
         */
        public function create_tables( $tables ) {
            $sql = '';
            if ( !is_array( $tables ) ) $tables = array();

            foreach ( $tables as $name => $columns ) {
                $sql .= "CREATE TABLE IF NOT EXISTS $name ($columns);";
            }

            if( !$this->cxn->multi_query( $sql ) ){
                die( "Error creating table: " . $this->cxn->errno .' '. $this->cxn->error );
            }
        }

        /**
         * Insert a row in table
         * @param  string $table
         * @param  array $data
         * @param  array $format
         * @return boolean
         */
        public function insert( $table, $data, $format ) {

            if ( empty($table) || empty($data) ) {
                return false;
            }

            //cast $data and $format to array
            $data = (array) $data;
            $format = (array) $format;

            //Build format string
            $format = $this->build_format($format);

            //prepare data
            list($fields, $placeholders, $values) = $this->prep_query($data);

            //prepend $format in to $values
            array_unshift($values, $format);

            //prepare statements
            if ( !( $stmt = $this->cxn->prepare("INSERT INTO {$table} ({$fields}) VALUES ({$placeholders})") ) ) {
                echo "Error preparating the query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //Dinamically binding
            if ( !call_user_func_array(array($stmt, 'bind_param'), $this->ref_values($values)) ) {
                echo "Error binding parameters: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //execute the query
            if (!$stmt->execute()) {
                echo "Error executing the insert query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //Check for succesful insertion
            if ( $stmt->affected_rows ) {
                return $stmt->insert_id;
            }

            return false;

        }

        /**
         * Update a row in a table
        * @param  string $table
        * @param  array $data
        * @param  string $format
        * @param  array $where
        * @param  string $where_format
        * @return boolean
         */
        public function update( $table, $data, $format, $where, $where_format ) {

            if ( empty($table) || empty($data) ) {
                return false;
            }

            //cast to array
            $data = (array) $data;
            $format = (array) $format;
            $where_format = (array) $where_format;

            //Build format string
            $format = $this->build_format($format);
            $where_format = $this->build_format($where_format);
            $format .= $where_format;

            //prepare data
            list($fields, $placeholders, $values) = $this->prep_query($data, 'update');
            list($where_clause, $where_values) = $this->prep_where($where);

            //prepend $format onto $values
            array_unshift($values, $format);
            $values = array_merge($values, $where_values);

            //prepare statements
            if ( !( $stmt = $this->cxn->prepare("UPDATE {$table} SET {$placeholders} WHERE ({$where_clause})") ) ) {
                echo "Error preparating the update query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }
            //bind params
            if ( !call_user_func_array(array($stmt, 'bind_param'), $this->ref_values($values)) ) {
                echo "Error binding parameters: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //execute
            if (!$stmt->execute()) {
                echo "Error executing the query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //Check for succesful insertion
            if ( $stmt->affected_rows ) {
                return true;
            }

            return false;

        }

        /**
         * Delete a row from a table
         * @param  string $table
         * @param  string|array $where
         * @param  string|array $where_format
         * @return false
         */
        public function delete( $table, $where = '', $where_format = '' ) {

            if ( !is_array( $where ) ) {
                $where = array( 'ID' => $where );
                $where_format = 'i';
            }

            $where_format = (array) $where_format;
            $where_format = $this->build_format($where_format);

            //prepare data
            list($where_clause, $where_values) = $this->prep_where($where);

            //prepend $format onto $values
            $values = $where_values;
            array_unshift($values, $where_format);

            //prepare statements
            if ( !( $stmt = $this->cxn->prepare("DELETE FROM {$table} WHERE {$where_clause}") ) ) {
                echo "Error preparating the delete query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //bind params
            if ( !call_user_func_array(array($stmt, 'bind_param'), $this->ref_values($values)) ) {
                echo "Error binding parameters: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //execute
            if (!$stmt->execute()) {
                echo "Error executing the query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //Check for succesful insertion
            if ( $stmt->affected_rows ) {
                return true;
            }

            return false;

        }

        /**
         * Select a row from a table
         * @param  string $table
         * @param  string $where
         * @param  string $where_format
         * @return array
         */
        public function select( $table, $where = '', $where_format = '' ) {

            if ( !is_array( $where ) ) {
                $where = array( 'ID' => $where );
                $where_format = 'i';
            }

            $where_format = (array) $where_format;
            $where_format = $this->build_format($where_format);

            //prepare data
            list($where_clause, $where_values) = $this->prep_where($where);

            //prepend $format onto $values
            $values = $where_values;
            array_unshift($values, $where_format);
            //prepare statements
            if ( !( $stmt = $this->cxn->prepare("SELECT * FROM {$table} WHERE {$where_clause}") ) ) {
                echo "Error preparating the query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //bind params
            if ( !call_user_func_array(array($stmt, 'bind_param'), $this->ref_values($values)) ) {
                echo "Error binding parameters: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //execute
            if (!$stmt->execute()) {
                echo "Error executing the query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            $results = $this->get_results($stmt);
            if ( $results ) {
                return $results;
            } else {
                throw new \Exception('Invalid query, no results founds.');
            }

        }

        /**
         * Select multiple row from a table
         * @param  string $table
         * @param  string $where
         * @param  string $where_format
         * @return array
         */
        public function select_array( $table, $where = '', $where_format = '' ) {

            if ( !is_array( $where ) ) {
                $where = array( 'ID' => $where );
                $where_format = 'i';
            }

            $where_format = (array) $where_format;
            $where_format = $this->build_format($where_format);

            //prepare data
            list($where_clause, $where_values) = $this->prep_where($where);

            //prepend $format onto $values
            $values = $where_values;
            array_unshift($values, $where_format);

            //prepare statements
            if ( !( $stmt = $this->cxn->prepare("SELECT * FROM {$table} WHERE {$where_clause}") ) ) {
                echo "Error preparating the query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //bind params
            if ( !call_user_func_array(array($stmt, 'bind_param'), $this->ref_values($values)) ) {
                echo "Error binding parameters: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //execute
            if (!$stmt->execute()) {
                echo "Error executing the query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            $results = $this->get_results($stmt, 'array');
            if ( $results ) {
                return $results;
            } else {
                throw new \Exception('Invalid query, no results founds.');
            }

        }

        /**
         * Select all the rows from a table
         * @param  string $table
         * @return array
         */
        public function select_all( $table ) {

            //prepare statements
            if ( !( $stmt = $this->cxn->prepare("SELECT * FROM {$table}") ) ) {
                echo "Error preparating the query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            //execute
            if (!$stmt->execute()) {
                echo "Error executing the query: (" . $this->cxn->errno . ") " . $this->cxn->error;
            }

            $results = $this->get_results($stmt, 'array');
            if ( $results ) {
                return $results;
            } else {
                throw new \Exception('Invalid query, no results founds.');
            }

        }

        /**
         * Get results from a query
         * @param  object $stmt
         * @param  string $type
         * @return array
         */
        private function get_results($stmt, $type = 'string') {
            $stmt->store_result();
            $meta = $stmt->result_metadata();

            while ( $field = $meta->fetch_field() ) {
                $params[] = &$row[$field->name];
            }

            call_user_func_array( array( $stmt, 'bind_result' ), $params );

            $results = array();
            while ( $stmt->fetch() ) {
            foreach( $row as $key => $val ) {
                $c[$key] = $val;
            }
            if ($type === 'array') {
                $results[] = $c;
            } else {
                $results = $c;
            }
            }
            if ( !empty( $results) ) return $results;
            return false;
        }

        /**
         * Build the format string for the query values
         * @param  array $format
         * @return string
         */
        private function build_format( $format ) {
            $format = implode('', $format);
            $format = str_replace('%', '', $format);
            return $format;
        }

        /**
         * Prepare data for a query
         * @param  array $data
         * @param  string $type
         * @return array
         */
        private function prep_query($data, $type = 'insert') {

            //instantiate $fields and $placeholders for looping
            $fields = '';
            $placeholders = '';
            $values = array();

            //loop through $data and build $fields, $placeholders and $values
            foreach ( $data as $field => $value ) {
                $fields .= "{$field},";
                $values[] = $value;

                if ( $type == 'update' ) {
                    $placeholders .= $field . '=?,';
                } else {
                    $placeholders .= '?,';
                }
            }

            //normalize $fields and $placeholder for inserting
            $fields = substr( $fields, 0, -1 );
            $placeholders = substr( $placeholders, 0, -1 );

            return array( $fields, $placeholders, $values );
        }

        /**
         * Prepare where data for a query
         * @param  array $where
         * @return array
         */
        private function prep_where($where) {
            $where_clause = '';
            $where_values = array();
            $count = 0;
            foreach ($where as $field => $value) {
                if ( $count > 0 ) {
                    $where_clause .= ' AND ';
                }
                $where_clause .= $field . '=?';
                $where_values[] = $value;
                $count++;
            }
            return array($where_clause, $where_values);
        }

        /**
         * Create references for query values
         * @param  array $array
         * @return array
         */
        private function ref_values( $array ) {
            $refs = array();
            foreach ( $array as $key => $value ) {
                $refs[$key] = &$array[$key];
            }
            return $refs;
        }

        /**
         * Hash a password
         * @param  string $password
         * @param  string $nonce
         * @return string
         */
        public function hash_password($password, $nonce) {
            $secureHash = hash_hmac('sha512', $password . $nonce, SITE_KEY);
            return $secureHash;
        }

        /**
         * Close the connection to database
         */
        private function close() {
            if ( !$this->cxn->close() ) {
                die('Can\'t close the connection');
            }
        }

    }

}

?>

然后我在我的模型类中使用这些方法,就像在Page类的这个例子中一样:

模型/ page.php文件

public function insert( $data ) {

            //prepare data
            list($data, $cats, $tags) = $this->prep_data($data);

            //insert the post
            $post = $this->db->insert( $this->table, $data, 'sssss' );

            //insert the post-cats relations
            if ( isset( $cats ) ) {
                foreach ( $cats as $cat ) {
                    $relation = array(
                        'post_id' => $post,
                        'term_id' => $cat,
                    );
                    $this->db->insert( 'term_relationships', $relation, 'ii' );
                }
            }

            //insert the post-tags relations
            if ( isset( $tags ) ) {
                foreach ( $tags as $tag ) {
                    $relation = array(
                        'post_id' => $post,
                        'term_id' => $tag,
                    );
                    $this->db->insert( 'term_relationships', $relation, 'ii' );
                }
            }

            return $post;
        }

以下是整个代码:Github

2 个答案:

答案 0 :(得分:1)

您可以将此功能用于近距离连接

   function __destruct()
     {
         //destroy open connection
     }

答案 1 :(得分:1)

看起来您正在使用常量连接到DB - 这意味着该类仅支持具有一组参数的连接。

您可以将连接设置为静态,然后无论您实例化该类多少次,每个脚本只能获得一个。 The PHP manual提供了静态使用的很好解释。

如果您需要第二次连接到不同的数据库,这将无法扩展,但到那时您将需要稍微重新考虑该类,并转移其他常量。

if ( !class_exists( 'DB' ) ) {

class DB {

    // make $cxn a static property shared between instances of this class
    private static $cxn = null;

    public function __construct() {
        $this->connect();
    }

    private function connect() {
        if(!is_null(self::$cxn)) {
            // a connection has already been tried, and succeeded
            return;
        }

        self::$cxn = new \mysqli( DB_HOST, DB_USER, DB_PASS, DB_NAME );
        if ( self::$cxn->connect_error ) {
            die( "Connection failed: " . self::$cxn->connect_errno . ' ' . self::$cxn->connect_error );
        }
    }