当PHP使用PDO访问数据库,需要长时间执行脚本时,会经常遇到'MySQLserverhasgoneaway'的错误。分析问题原因:由于脚本长时间没有和数据库通信,导致数据库连接超时,服务器断开。此时使用断开的数据库连接操作数据库(CRUD)会产生'MySQLserverhasgoneaway'错误信息。解决方法是长时间运行的脚本需要与服务器保持心跳,一旦检测到断开连接,需要重新连接数据库。考虑到保持最小的数据库负载(检测手段的开销小,心跳频率不能太频繁)和脚本的高健壮性(需要更高频率的心跳),可以选择不同的心跳测试策略和心跳频率。下面的代码提供了一个解决方案。数据库连接被单片封装。每次获取数据库连接时,都会判断是否需要检测连接是否仍然有效。如果连接失败,将重建连接。在脚本的健壮性和服务器的压力之间保持最佳平衡lastCheckTime=time();}publicstaticfunctioninstance(){if(NULL==self::$instance){self::$instance=newDBConnection();}returnself::$instance;}publicfunctiondbh(){$this->ensureConnection2();返回$this->dbh;}privatefunctionensureConnection(){if(is_null($this->dbh))return$this->makeConnection();尝试{$status=$this->dbh->getAttribute(PDO::ATTR_SERVER_INFO);error_log('MySQL服务器检查过');}catch(PDOException$e){if((int)$e->errorInfo[1]==2006&&$e->errorInfo[2]=='MySQLserver已经消失'){error_log("MySQLserver已经消失,尝试重新连接...");返回$this->makeConnection();}error_log('获取数据库服务器属性失败:'.$e->getMessage());}return$this->dbh;}privatefunctionensureConnection2(){if(is_null($this->dbh))return$this->makeConnection();尝试{$now=time();如果($now-$this->lastCheckTime>self::RECHECK_FREQUENCY){$this->lastCheckTime=$now;$status=$this->dbh->query("select1");error_log('MySQL服务器已检查过');}}catch(PDOException$e){if((int)$e->errorInfo[1]==2006&&$e->errorInfo[2]=='MySQLserverhasgoneaway'){error_log("MySQL服务器有走了,尝试重新连接...");返回$this->makeConnection();}error_log('获取数据库服务器属性失败:'.$e->getMessage());}return$this->dbh;}privatefunctionmakeConnection(){try{$options=array(PDO::MYSQL_ATTR_INIT_COMMAND=>"setnames'utf8'",PDO::ATTR_PERSISTENT=>false,PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION);$this->dbh=newPDO(DB_DSN,DB_USER,DB_PASSWORD,$options);返回$this->dbh;}catch(PDOException$e){error_log('连接失败:'.$e->getMessage());出口();}返回空值;}}
