前话
在工作中,有时候一些后台脚本需要长时间的运行,同时可能在连接数据库后,长时间不与数据库服务端交互。此时,服务器可能会断开与客户端的连接。从而客户端再次交互时就会出现""连接丢失。此次修改达到的效果:断线重连机制对应用层完全透明,无需自己重复发送请求。
错误原因
Mysql has gone away 或者 Lost connection to MySQL server 或者 Error while sending QUERY packet
- 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’;
制造错误
造一个表
DROP TABLE IF EXISTS `nt_vm_message_idempotent`;
CREATE TABLE `nt_vm_message_idempotent` (
`uid` mediumint(15) NOT NULL DEFAULT 0,
`message_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '消息ID',
`message_content` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '消息内容',
`product_status` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否生产成功到mq',
`consume_status` tinyint(1) NOT NULL COMMENT '是否消费成功',
`create_time` int(10) UNSIGNED NOT NULL DEFAULT 0,
`update_time` int(10) UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`message_id`) USING BTREE,
UNIQUE INDEX `unique_message_id`(`message_id`) USING BTREE,
INDEX `uid`(`uid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
然后造一个程序
public function actionInsert(){
try{
//设置你的MYSQL的wait_timeout = 30,interactive_timeout也要设置,否则不生效 为了测试
Yii::app()->db->createCommand('SET SESSION wait_timeout = 30;SET SESSION interactive_timeout = 30;')->execute();
$result = Yii::app()->db->createCommand("show global variables like '%timeout'")->queryAll();
print_r($result);
$sql = "insert into nt_vm_message_idempotent ( `uid` , `message_id` , `message_content` , `product_status`,`consume_status` , `create_time`, `update_time`) values
('98468', '100', 'asdfsda', 1,0,1,2)";
Yii::app()->db->createCommand($sql)->execute();
sleep(31);
$sql = "UPDATE nt_vm_message_idempotent SET consume_status=1,update_time=1623412774 WHERE message_id = '100'";
//再加上@符号抑制错误 要不下面捕捉不到
@Yii::app()->db->createCommand($sql)->execute();
}catch (Exception $e){
echo $e->getMessage();
if(strpos($e->getMessage(),'UPDATE nt_vm_message_idempotent SET') !== false){
//yii重连数据库 需要解决这个问题需要打开注释
//Yii::app()->db->setActive(false);
$sql = "UPDATE nt_vm_message_idempotent SET consume_status=1,update_time=1623412774 WHERE message_id = '100'";
@Yii::app()->db->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 `t_biubiu` (`value`) VALUES (:yp0). Bound with :yp0='insert8'' in E:\phpWorks\framework\db\CDbCommand.php:362
sleep有效果了。
大部分情况就是超时导致的,尤其是脚本执行时间太长
解决办法
方法 | 做法 |
---|---|
1 | 在my.cnf里wait_timeout改大一些,并不能一劳永逸 |
2 |
代码中遇到超时重连 你需要在自己的PHP数据库连接处增加大致如下代码。
if( in_array(mysql_errno(), array(2006, 2013))){ mysql_close(); mysql_connect(...); mysql_query(...); } |
3 | 检查是不是Mysql连接过多,并发太高,忘记释放连接(一般出现这种情况不是所有例句而是单个表,请你先修复表一般都能解决这类问题。) |