mysql作为php的黄金搭档和互联网上应用最普遍的数据库,免不了每天与之打交道,很多朋友在熟悉swoole的使用以后,也趟平了很多坑,准备实战了,终于上线了,正愉快的体验swoole带来的巨大改进,忽然数据库操做bug了,大量报mysql server gone away, 因而swooler内心千万之草尼马奔腾而过,大骂,swoole误我~~~php
且慢!!!这真不是swoole的问题!!!!不是swoole的问题!!!!不是swoole的问题!!!!(重要的事情说三遍)mysql
缘由sql
不是swoole的问题,那他的缘由是什么呢?数据库
这要从mysql的机制提及,mysql自己是一个多线程的程序,每一个链接过来,会开一个线程去处理相关的query, 因此mysql为了不占着毛坑不拉屎,会按期回收长时间没有任何query的链接(时间周期受wait_timeout配置影响),因此在swoole中,因为是一个长驻内存的服务,咱们创建了一个mysql的链接,不主动关闭 或者是用pconnect的方式,那么这个mysql链接会一直保存着,而后长时间没有和数据库有交互,就主动被mysql server关闭了,以后继续用这个链接,就报mysql server gone away了。服务器
解决方案swoole
知道问题产生的缘由,就能够对症下药了。多线程
方案1: 修改mysql的wait_timeout值为一个很是大的值。spa
此方法不太可取,可能会产生大量的sleep链接,致使mysql链接上限了, 建议不使用。线程
方案2:每次query以前主动进行链接检测orm
若是是用mysqli,可用内置的mysqli_ping
示例:
if (!$mysqli->ping()) {mysqli->connect(); //重连
}
若是是pdo,能够检测mysql server的服务器信息来判断:
try {
$pdo->getAttribute(\PDO::ATTR_SERVER_INFO);
} catch (\Exception $e) {
if ($e->getCode() == 'HY000') {
$pdo = new PDO(xxx); //重连
} else {
throw $e;
}
}
但这个方案有个缺点:额外多一次请求,因此改进方法: 用一个全局变量存放最后一次query的时间,下一次query的时候先和如今时间对比一下,超过waite_timeout再重连. 或者也能够用swoole_tick定时检测。
方案3:被动检测, 每次query用try catch包起来,若有mysql gone away异常,则从新链接,再执行一次当前sql.
示例:
try {
query($sql);
} catch (\Exception $e) {
if ($e->getCode() == 'HY000') {
reconnect(); //重连
query($sql)
} else {
throw $e;
}
}
方案4: 用短链接,务必每次操做完以后,手动close
额外问题:mysql为何须要链接池?