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:362
sleep有效果了。
大部分情况就是超时导致的,尤其是脚本执行时间太长
解决办法
如果运维不同意 改变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执行时间较长, ...
随机推荐
- Java线程池基础
目录: 一.线程池概述 二.线程池参数 三.线程池的执行过程 四.线程池的主要实现 五.线程池的使用 六.线程池的正确关闭方式 七.线程池参数调优 一.线程池概述 1.线程池类 目前线程池类一般有两个 ...
- logcat粗略了解(一)
Logcat Logcat介绍:logcat是android的一个命令行工具,用于的到程序的log信息 Logcat命令格式: [adb] logcat [<option>]…[<f ...
- Spring boot 梳理 - Spring boot自动注册DispatcherServlet
spring boot提供的DispatcherServlet的name就是“dispatcherServlet”. 源码 public ServletRegistrationBean dispatc ...
- 【ASP.NET基础--MVC】MVC视图基础语法学习
初步接触.net MVC的视图语法,很多东西都不太熟悉,感觉跟之前的aspx以及html都有一些区别,最近看别人的代码,一边看一边研究,现把学到的东西在这里记录一下,以便日后翻阅. 第一部分:基础知识 ...
- Spring Boot认证:整合Jwt
背景 Jwt全称是:json web token.它将用户信息加密到token里,服务器不保存任何用户信息.服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证. 优点 简洁: 可以通过 ...
- 安装/删除MySQL数据库
MySQL的数据存储目录为data,data目录通常在C:\Documents and Settings\All Users\Application Data\MySQL\MySQL Server 5 ...
- golang grpc 详解
https://segmentfault.com/a/1190000007880647
- 分库分表(4) ---SpringBoot + ShardingSphere 实现分表
分库分表(4)--- ShardingSphere实现分表 有关分库分表前面写了三篇博客: 1.分库分表(1) --- 理论 2.分库分表(2) --- ShardingSphere(理论) 3.分库 ...
- Android OkHttp + Retrofit 取消请求的方法
本文链接 前言 在某一个界面,用户发起了一个网络请求,因为某种原因用户在网络请求完成前离开了当前界面,比较好的做法是取消这个网络请求.对于OkHttp来说,具体是调用Call的cancel方法. 如何 ...
- rest_framework视图
知识预览 视图 回到顶部 视图 使用混合(mixins) 上一节的视图部分: from rest_framework.views import APIView from rest_framewor ...