Yii 数据库重连告别General error: 2006 MySQL server has gone away
General error: 2006 MySQL server has gone away
- 错误原因
- 制造错误
- 解决办法
- 最新办法
错误原因
Mysql has gone away
- MySQL 服务宕了
- mysql连接超时 show global variables like ‘%timeout’;
- mysql请求链接进程被主动kill show global status like ‘com_kill’;
- Your SQL statement was too large. show global variables like ‘max_allowed_packet’;
制造错误
造一个表
-- ----------------------------
-- Table structure for t_biubiu
-- ----------------------------
DROP TABLE IF EXISTS `t_biubiu`;
CREATE TABLE `t_biubiu` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `value` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;然后造一个程序
public function actionInsert(){
        Biubiu::model()->findAll();
        $result = Yii::app()->db->createCommand("show global variables like '%timeout'")->queryAll();
        self::show_vars($result);
        for($index = 1 ;$index< 10;$index++){
            $model_ = new Biubiu();
            $model_->value = "insert".$index;
            if($index == 8){
                sleep(31);
            }
            $model_->save();
        }
        $model = new Biubiu();
        $model->value = "insert4";
        $model->save();
     }设置你的MYSQL的wait_timeout = 30,interactive_timeout也要设置,否则不生效
执行的时候就会抛异常:
exception 'CDbException' with message 'CDbCommand failed to execute the SQL statement: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away. The SQL statement executed was: INSERT INTO `t_biubiu` (`value`) VALUES (:yp0). Bound with :yp0='insert8'' in E:\phpWorks\framework\db\CDbCommand.php:362sleep有效果了。
大部分情况就是超时导致的,尤其是脚本执行时间太长
解决办法
如果运维不同意 改变wait_timeout的值:
| 方法 | 做法 | 
|---|---|
| 1 | wait_timeout改大一些,并不能一劳永逸 | 
| 2 | 代码中遇到超时重连 | 
| 3 | 检查是不是Mysql连接过多,并发太高,忘记释放连接 | 
解决方法推荐
例如,读写分离的 JDbConnection。在调用save delete方法的时候执行ensureActive() 。注意 @,否则异常发生的时候PHP ERROR直接挂掉。
<?php
/**
 * JDbConnection(Database Connection Manager) class is a manager of database connections.
 *
 * for the purpose of database read/write splitting.
 * It override the createCommand method,
 * detect the sql statement to decide which connection will be used.
 * Default it use the master connection.
 *
 */
class JDbConnection extends CDbConnection
{
    /**
     * @var array $slaves.Slave database connection(Read) config array.
     * The array value's format is the same as CDbConnection.
     * <code>
     * 'components'=>array(
     * 'db'=>array(
     * 'class' => 'JDbConnection',
     * 'connectionString'=>'MySQL://<master>',
     * 'slaves'=>array(
     * array('connectionString'=>'mysql://<slave01>'),
     * array('connectionString'=>'mysql://<slave02>'),
     * )
     * )
     * )
     * </code>
     */
    public $slaves = array();
    /**
     * Whether enable the slave database connection.
     * Defaut is true.Set this property to false for the purpose of only use the master database.
     *
     * @var bool $enableSlave
     */
    public $enableSlave = true;
    /**
     * @var CDbConnection
     */
    private $_slave;
    /**
     * Creates a CDbCommand object for excuting sql statement.
     * It will detect the sql statement's behavior.
     * While the sql is a simple read operation.
     * It will use a slave database connection to contruct a CDbCommand object.
     * Default it use current connection(master database).
     *
     * @override
     * @param string $sql
     * @return CDbCommand
     */
    public function createCommand($query = null)
    {
        if ($this->enableSlave && !$this->getCurrentTransaction() && self::isReadOperation($query)) {
            return $this->getSlave()->createCommand($query);
        } else {
            return parent::createCommand($query);
        }
    }
    /**
     * Construct a slave connection CDbConnection for read operation.
     *
     * @return CDbConnection
     */
    public function getSlave()
    {
        if (!isset($this->_slave)) {
            foreach ($this->slaves as $slaveConfig) {
                if (!isset($slaveConfig['class']))
                    $slaveConfig['class'] = 'CDbConnection';
                try {
                    if ($slave = Yii::createComponent($slaveConfig)) {
                        Yii::app()->setComponent('dbslave', $slave);
                        $this->_slave = $slave;
                        break;
                    }
                } catch (Exception $e) {
                    Yii::log('Create slave database connection failed!', 'warn');
                    continue;
                }
            }
            if (!$this->_slave) {
                $this->_slave = clone $this;
                $this->_slave->enableSlave = false;
            }
        }
        return $this->_slave;
    }
    /**
     * Detect whether the sql statement is just a simple read operation.
     * Read Operation means this sql will not change any thing ang aspect of the database.
     * Such as SELECT,DECRIBE,SHOW etc.
     * On the other hand:UPDATE,INSERT,DELETE is write operation.
     *
     * @return bool
     */
    public function isReadOperation($sql)
    {
        return !!preg_match('/^\s*(SELECT|SHOW|DESCRIBE|PRAGMA)/i', $sql);
    }
    /**
     * 确保数据库连接有效
     *
     * @params bool $isSlaveping主库还是从库
     * @return void
     */
    public function ensureActive($isSlave = true)
    {
            if ($this->getActive()) {
                try {
                    @$this->getPdoInstance()->query('SELECT 1');
                } catch (PDOException $e) {
                    $this->setActive(false);
                    $this->setActive(true);
                }
            }
    }
}
调用示例:
 Yii::app()->db->ensureActive();另外一种方法
执行SQL之前执行:
Yii::$app->db->createCommand('SET SESSION wait_timeout = 28800;')->execute();最新办法
避免每次多请求了一次数据库。只有在遇到问题时进入异常处理,重试的时候Yii会自动进行重连[不确定]。
public static function retry($params, $call){
    for($retry = 0; $retry < 3;$retry++){
        try{
            if($params instanceof CModel){
                return $params->$call();
            }
        }catch(CDbException $e){
            if (!(strpos($e, "error: 2006") && !strpos($e, "error: 2013"))) {
                throw new Exception($e->getMessage(), 520);
            }
        }
    }
    return false;
}2017年4月9日 更新
最近发现,公司所用的yii framework1.1的框架,和官方下载的不太一样。
下载最新框架,测试代码如下,我将mysql设置为wait_timeout=30, interactive_timeout=30
class DbTestCommand extends CConsoleCommand {
    public function actionInsert(){
        $sql = "insert into adv_pro ( `name` , `int_value`) values ('insert', 100)";
        Yii::app()->localdb->createCommand($sql)->execute();
        sleep(31);
        $sql = "insert into adv_pro ( `name` , `int_value`) values ('insert', 200)";
        Yii::app()->localdb->createCommand($sql)->execute();
    }
}结果就出现了:
PHP Error[2]: PDOStatement::execute(): MySQL server has gone away
    in file D:\work_project\framework\db\CDbCommand.php at line 336
#0 D:\work_project\framework\db\CDbCommand.php(336): PDOStatement->execute()
#1 D:\work_project\task\protected\commands\DbTestCommand.php(19): CDbCommand->execute()
#2 unknown(0): DbTestCommand->actionInsert()再加上@符号抑制错误
@Yii::app()->localdb->createCommand($sql)->execute();结果异常就抛出来了:
exception 'CDbException' with message 'CDbCommand failed to execute the SQL statement: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away. The SQL statement executed was: insert into adv_pro ( `name` , `int_value`) values ('insert', 200)' in D:\work_project\framework\db\CDbCommand.php:363
Stack trace:
#0 D:\work_project\task\protected\commands\DbTestCommand.php(19): CDbCommand->execute()那么可以把框架的db/CDbCommand.php内的execute方法改一下,改成:
if($params===array())
    @$this->_statement->execute();
else
    @$this->_statement->execute($params);这样就能捕获到这个异常了。
那么据此,可以为CDbCommand.php增加一个方法:
public function sqlDbExecute($params=array()){
    $e = new Exception("sqlDbExecute failed three times", 10001);
    for ($count=0;$count<3;$count++){
        try {
            $result = $this->execute($params);
            return $result;
        } catch (Exception $e) {
               Yii::log('Error in sqlDbExecute SQL: '.$this->getText(),CLogger::LEVEL_ERROR,'system.db.CDbCommand');
            $this->_connection->setActive(true);
            //If not found 2006 then throw up
            if (!strpos($e, "error: 2006")) {
                   throw new Exception($e,10001);
            }
        }
    }
    throw new Exception($e,10001);
}Yii 数据库重连告别General error: 2006 MySQL server has gone away的更多相关文章
- ThinkPHP出现General error: 2006 MySQL server has gone away的解决方法
		错误: #13 {main}SQLSTATE[HY000]: General error: 2006 MySQL server has gone awayFILE: \ThinkPHP\Library ... 
- General error 2006 MySQL server has gone away
		写入配置文件的办法: max_allowed_packet = 16M //但是这种有时候不支持,1024*1024*16这种有的也不支持 max_allowed_packet = 16777216 ... 
- flask+mako+peewee(下)(解决了Error 2006: MySQL server has gone away)
		这篇主要介绍在这次项目中使用的peewee 文档地址:http://peewee.readthedocs.org/en/latest/index.html 首先我们要初始化一个数据库连接对象.这里我使 ... 
- mysql error: (2006, 'MySQL server has gone away')
		max_allowed_packet=16M wait_timeout= interactive_timeout = vim /etc/my.cnf mysqld 中加入上面的内容. 
- MySql General error:2006
		当启用模块时发生Mysql数据库错误,错误信息见附件,实际是“General error: 2006 MySQL server has gone away......”错误. 解决方法:找到my.in ... 
- 2006 - MySQL server has gone away
		mysql出现ERROR : (2006, 'MySQL server has gone away') 的问题意思就是指client和MySQL server之间的链接断开了. 造成这样的原因一般是s ... 
- SQLyog恢复数据库报错解决方法【Error Code: 2006 - MySQL server has gone away】
		https://blog.csdn.net/niqinwen/article/details/8693044 导入数据库的时候 SQLyog 报错了 Error Code: 2006 – MySQL ... 
- MYSQL导入数据报错|MYSQL导入超大文件报错|MYSQL导入大数据库报错:2006 - MySQL server has gone away
		导SQL数据库结构+数据时,如果数据是批量插入的话会报错:2006 - MySQL server has gone away. 解决办法:找到你的mysql目录下的my.ini配置文件(如果安装目录没 ... 
- Yii2 解决2006 MySQL server has gone away问题
		Yii2 解决2006 MySQL server has gone away问题 Yii2版本 2.0.15.1 php后台任务经常包含多段sql,如果php脚本执行时间较长,或者sql执行时间较长, ... 
随机推荐
- 微服务SpringCloud之注册中心Consul
			Consul 介绍 Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其它分布式服务注册与发现的方案,Consul 的方案更“一站式”,内置了服务注册与发 ... 
- 基于python的scrapy环境搭建
			0.1安装python软件 32位机的电脑安装python-3.6.3.exe 64位机的电脑安装python-3.6.3-amd64.exe 0.1.1 python环境搭建 执行安装程序 选择Ad ... 
- python-字符编码、字符串格式化、进制转化、数据类型、列表、元组、字典总结
			目录: 一.字符编码 二.字符串格式化 三.进制转换 四.数据类型及其操作 五.字符串转换 六.列表 七.元组 八.字典 一.字符编码: 计算机由美国人发明,最早的字符编码为ASCII,只规定了英文字 ... 
- Android类似日历的翻转控件
			最近写了个翻转面板的控件拿出来与大家分享一下,类似日历的那种,写的比较简单有需要的可以直接拿去用.直接上效果图吧,代码我放在百度云了,有问题的话直接回复就好呢,大家一起交流下. http://pan. ... 
- docker容器添加对外映射端口
			一般在运行容器时,我们都会通过参数 -p(使用大写的-P参数则会随机选择宿主机的一个端口进行映射)来指定宿主机和容器端口的映射,例如 docker run -it -d --name [contain ... 
- jQuery常用方法(五)-jQuery CSS
			JQuery CSS 方法说明 css( name ) 访问第一个匹配元素的样式属性. css( properties ) 把一个"名/值对"对象设置为所有匹配元素的样式属性. $ ... 
- 我的mongoDb之旅(一)
			开发环境 php版本:7.0.10 mongodb版本:1.5 开发框架:tp5 数据库工具:navicat12formongodb 可以参考的外部文件链接 tp5中mongodb的扩展说明:http ... 
- resmgr:cpu quantum等待事件 触发的bug问题
			1>resmgr:cpu quantum等待事件 触发的bug问题 (处理心得) 1.客户反馈数据库服务器在某个时间段总是特别繁忙,获取awr报告分析繁忙原因 
- 杂谈:开发人员如何进行复杂业务的学习?让boss刮目相看
			一点小拙见,欢迎指正 一.概述 大型复杂的软件系统,是有许多人共同协作完成的,有些产品的业务是很复杂的,其在需求文档,及开发规范上都做得很好,不然维护的人越多,没有文档和规范去限制,岂不更加乱套. 如 ... 
- LeetCode_225-Implement Stack using Queues
			使用队列实现栈的操作 class MyStack { public: /** Initialize your data structure here. */ MyStack() { } /** Pus ... 
