我使用下面的代码进行数据库连接
class Database extends PDO{
function __construct(){
try {
parent::__construct(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
} catch(PDOException $e){
Logger::newMessage($e);
logger::customErrorMsg();
}
}
}
Run Code Online (Sandbox Code Playgroud)
像登录,获取数据等所有事情都运行良好.现在我突然收到异常错误消息
Message: SQLSTATE[08004] [1040] Too many connections
Code: 1040
Run Code Online (Sandbox Code Playgroud)
如何解决这个错误?
我有一个模型类,我正在创建新的数据库.
class Model {
protected $_db;
public function __construct(){
//connect to PDO here.
$this->_db = new Database();
}
}
Run Code Online (Sandbox Code Playgroud)
我制作的每一个模型,都是从模型类扩展而来的.
Mic*_*ski 11
因为您的Model类Database在其构造函数中实例化一个新对象,所以每次实例化一个Model(或任何扩展它的类)时,您实际上都在打开一个新的数据库连接.如果你创建了几个Model对象,那么每个对象都有自己独立的数据库连接,这种连接不常见,通常是不必要的,不能很好地利用资源,但是由于它耗尽了所有服务器的可用连接,因此也是有害的.
例如,循环以创建Model对象数组:
// If a loop creates an array of Model objects
while ($row = $something->fetch()) {
$models[] = new Model();
}
// each object in $models has an independent database connection
// the number of connections now in use by MySQL is now == count($models)
Run Code Online (Sandbox Code Playgroud)
该解决方案是使用依赖注入和传递的Database对象为Model::__construct(),而不是让它来实例化其自身.
class Model {
protected $_db;
// Accept Database as a parameter
public function __construct(Database $db) {
// Assign the property, do not instantiate a new Database object
$this->_db = $db;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,使用它,控制代码(将实例化您的模型的代码)本身应该new Database()只调用一次.然后,必须将控制代码创建的对象传递给所有模型的构造函数.
// Instantiate one Database
$db = new Database();
// Pass it to models
$model = new Model($db);
Run Code Online (Sandbox Code Playgroud)
对于您实际需要为模型使用不同的独立数据库连接的用例,您可以将其交给另一个.特别是,这对测试很有用.您可以替换测试数据库对象或模拟对象.
// Instantiate one Database
$db = new Database();
$another_db = new Database();
// Pass it to models
$model = new Model($db);
$another_model = new Model($another_db);
Run Code Online (Sandbox Code Playgroud)
正如评论中所提到的,使用持久连接可能是一种解决方案,但不是我建议的解决方案.PDO将尝试重用具有相同凭据的现有连接(与您的所有连接一样),但您不一定希望跨脚本执行缓存连接.如果你决定这样做,你需要将属性传递给Database构造函数.
try {
// Set ATTR_PERSISTENT in the constructor:
parent::__construct(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS, array(PDO::ATTR_PERSISTENT => true));
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}
Run Code Online (Sandbox Code Playgroud)
相关文档如下:http://php.net/manual/en/pdo.connections.php#example-950
使用单例模式(也不推荐),您至少可以将其减少为模型代码中的搜索/替换.本Database类需要一个静态属性,以保持本身的连接.然后模型调用Database::getInstance()而不是new Database()检索连接.您需要在模型代码中进行搜索和替换以替换Database::getInstance().
虽然它运行良好并且不难实现,但在您的情况下,它会使测试更加困难,因为您必须Database使用相同名称的测试类替换整个类.您不能轻易地在实例的基础上替换测试类.
将单例模式应用于Database:
class Database extends PDO{
// Private $connection property, static
private static $connection;
// Normally a singleton would necessitate a private constructor
// but you can't make this private while the PDO
// base class exposes it as public
public function __construct(){
try {
parent::__construct(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
} catch(PDOException $e){
Logger::newMessage($e);
logger::customErrorMsg();
}
}
// public getInstance() returns existing or creates new connection
public static function getInstance() {
// Create the connection if not already created
if (self::$connection == null) {
self::$connection = new self();
}
// And return a reference to that connection
return self::$connection;
}
}
Run Code Online (Sandbox Code Playgroud)
现在您只需要更改Model要使用的代码Database::getInstance():
class Model {
protected $_db;
public function __construct(){
// Retrieve the database singleton
$this->_db = Database::getInstance();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
18832 次 |
| 最近记录: |