问题描述:
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总结