php yii2跑数出现mysql-gone-away-2006解决

在使用PHP的Yii2框架运行长时间任务时遇到MySQL gone-away错误2006。该问题与JDBC不同,可能是由于Yii2未正确释放连接导致。解决方案是重载yiidbCommand的`execute()`和`queryInternal()`方法,以在出现错误2006时重新打开和关闭连接。通过修改数据库配置,将默认的command Class替换为自定义的子类command。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:

Error Info:

Array
(
    [0] => HY000
    [1] => 2006
    [2] => MySQL server has gone away
)

"用php跑数据 任务时间过长,每次都会出现这个,能帮忙把这个超时时间设置到最大吗,下周我们仔细看看这个是啥问题,之前用JDBC跑数 不会出现这个问题,应该是php,yii2一直拿connection没有释放"

JDBC中!=null 就close  这种事我觉得应该是框架做的 

上述可知用JDBC无此问题,用yii2频繁出现,定位是yii2的问题,gone-away意思是连接不见了,断掉了,那么有没有colse和open的方法呢,断掉了我们手动去open一下

查了一下open和close的写法为

Yii::$app->db->open();
Yii::$app->db->close();

思路是在

try{

//code

}catch(Exception $e){

//去判断 $e是不是2006,然后去open一下,然后再colse一下

}

每个方法都去写一个这样的try{}catch{}不是很科学,通常的做法是在顶级父类的afterAction或入口去拦截这样的错误

最终选取的做法,重载yii\db\Command的execute和queryInternal方法

阅读yii\db\Command源码可知

execute()--->所有的增删改操作的入口

queryInternal()---->所以的查询操作的入口

最终书写一个Command去继承yii\db\Command,然后在数据库db配置中把默认的command Class 改成我们自己写的子类command

scm 修改示例

'db => [
        'class'       => 'yii\db\Connection',
        'dsn'         => $scm_config['db.dsn'],
        'username'    => $scm_config['db.username'],
        'password'    => $scm_config['db.password'],
        'charset'     => 'utf8',
        'tablePrefix' => 'tb_',
        'commandClass' => 'app\components\Command'  //自己写的子类Command
    ],


<?php
/**
 * Created by PhpStorm.
 * User: liuyifan
 * Date: 16/09/17
 * Time: 下午 04:24
 */

namespace app\components;


use yii\db\Exception;
use yii\db\Command as YiiCommand;

/**
 * Class Command
 * @package app\components
 * 解决mysql-gone-away 2006,2013的问题
 */
class Command extends YiiCommand
{
    const SLEEP_TIME = 60;

    /***
     * @return int
     * @throws Exception
     * 所有[增删改]操作调用
     */
    public function execute()
    {
        try {
            return parent::execute();
        } catch (Exception $e) {
            if ($e->errorInfo[1] == 2006 || $e->errorInfo[1] == 2013) {
                echo '[Mysql-'.$e->errorInfo[1].'] problem handler with app\components\Command execute()...'.PHP_EOL;
                $this->db->close();
                $this->db->open();
                $this->pdoStatement = null ;
                sleep(self::SLEEP_TIME);
                return parent::execute();
            }else{
                throw $e;
            }
        }
    }


    /***
     * @param string $method
     * @param null $fetchMode
     * @return mixed
     * @throws Exception
     * 所有[查操作]都会调用queryInternal方法
     */
    protected function queryInternal($method, $fetchMode = null){
        try {
            return parent::queryInternal($method, $fetchMode);
        } catch (Exception $e) {
            if ($e->errorInfo[1] == 2006 || $e->errorInfo[1] == 2013) {
                echo '[Mysql-'.$e->errorInfo[1].'] problem handler with app\components\Command queryInternal()...'.PHP_EOL;
                $this->db->close();
                $this->db->open();
                $this->pdoStatement = null ;

                sleep(self::SLEEP_TIME);
                return parent::queryInternal($method, $fetchMode);
            }else{
                throw $e;
            }
        }
    }

}


附上测试类

//php yii test/my-sql-gone-away-2006
    public function actionMySqlGoneAway2006() {
        $this->print_f('MySql_Gone_Away_2006  test......');



        $seconds = 20;
        $hours = $seconds/3600;
        $minutes = $seconds/60;

        $this->setMysqlInteractiveTimeout($seconds-10);
        $this->setMysqlWaitTimeout($seconds-10);

        Yii::$app->db->createCommand("select * from test")->queryAll();
        $this->print_f('sleep start ....');
        $this->print_f("sleep time {$hours}h={$minutes}m={$seconds}s ....");
        sleep($seconds);
        $this->print_f('sleep end ....');

        Yii::$app->db->createCommand("insert into test(name,age) VALUES ('liuyifan',40)")->execute();
        Yii::$app->db->createCommand("insert into test(name,age) VALUES ('xiuyuding',3)")->execute();
        Yii::$app->db->createCommand("insert into test(name,age) VALUES ('wangyong',28)")->execute();
        Yii::$app->db->createCommand("insert into test(name,age) VALUES ('guandongdong',26)")->execute();
        Yii::$app->db->createCommand("insert into test(name,age) VALUES ('changhuanhuan',-1)")->execute();
        Yii::$app->db->createCommand("insert into test(name,age) VALUES ('wangdandan',-1)")->execute();

    }

    public function setMysqlInteractiveTimeout($seconds) {
        $sql = "set interactive_timeout=$seconds";
        Yii::$app->db->createCommand($sql)->execute();
    }

    public function setMysqlWaitTimeout($seconds) {
        $sql = "set wait_timeout=$seconds";
        Yii::$app->db->createCommand($sql)->execute();
    }


附造成mysql-gone-away-2006总结


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值