这次来是因为上篇文章swoole实现多对多群聊进阶篇的pdo链接有效时间好像不是那么的长!!!导致数据完全丢失!!!
通过测试,发现pdo链接在一个小时左右后就不会再往数据库插入数据了,而且sql语句执行也不会报错,具体什么情况一时间还不清楚,然后开始找是不是pdo链接不支持长链接,百度了一下,果然需要配置才能实现长链接
PDO有一项参数,名为PDO::ATTR_PERSISTENT是个booleans值,默认不开启,
屁颠屁颠的开启跑去测试后发现,还是不行,还是会断开,这我又想不通了,如果断开,执行sql理应会报错啊,然后在try catch 语句下手
try {
$stmt = $this->pdo->prepare($sql);
$stmt->execute();
} catch (Exception $e) {
$this->pdo = new PDO(
"mysql:host=********;dbname=******;charset=utf8;",
"********",
"********",[\PDO::ATTR_CASE => \PDO::CASE_NATURAL]
);
}
这里的意图是,如果执行sql报错,我就从新初始化pdo链接,不过结果也不尽人意,执行sql什么事都没有,数据库没有记录,也不报错,想来想去,只能是小弟搞得鬼了,要把小弟拉出去祭天!
上篇文章中的小弟相关的代码
//创建token找几个小弟
$this->ws->set([
'worker_num' => WORKER_NUM,
'task_worker_num' => TASK_WORKER_NUM,
]);
//token线程监听
$this->ws->on("task", [$this, 'onTask']);
$this->ws->on('finish',[$this,'onFinish']);
我就想,会不会是小弟线程导致的问题,pdo链接被他吃掉了,后来一看代码
/**
* 监听用户链接事件,链接时需要带用户id与房间id参数,再把用户存到房间域中
*/
public function onOpen($server, $request){
//加入房间域
$this->redis->hset($request->get['room'], $request->get['uid'], $request->fd);
//加入组集合
$this->redis->sadd('group', $request->get['room']);
//链接后,插入一条日志
self::recordLog($request->fd, $request->get['uid'], $request->get['room'], "add");
}
在用户开始链接websocket的时候,我也会去数据库插一条记录,并没有用到小弟,所以小弟的嫌疑就没了…
这下就没辙了,只好换跳思路实现功能了,跑到swoole官网,找到了异步MySQL客户端相关的介绍,本着试一试的心态,把代码贴进去
public $pdo = null;
public $dbdata = null;
public $sql = null;
public function __construct()
{
...//其他代码
$this->pdo = new swoole_mysql();
$this->dbdata = array(
'host' => '******',
'port' => 3306,
'user' => '*********',
'password' => '*******',
'database' => '*********',
'charset' => 'utf8', //指定字符集
'timeout' => 2, // 可选:连接超时时间(非查询超时时间),默认为SW_MYSQL_CONNECT_TIMEOUT(1.0)
);
...//其他代码
}
...//其他代码
//房间记录 fd-uid-room
private function recordLog($fd, $uid, $room_id, $type)
{
switch ($type){
case "add":
$this->sql = "***********";
break;
case "close":
$this->sql = "**********";
break;
}
try {
$this->pdo->connect($this->dbdata, function ($db, $r) {
if ($r === false) {
var_dump($db->connect_errno, $db->connect_error);
die;
}
$this->pdo->query($this->sql, function(swoole_mysql $db, $r) {
if ($r === false)
{
var_dump($db->error, $db->errno);
}
elseif ($r === true )
{
var_dump($db->affected_rows, $db->insert_id);
}
$db->close();
});
});
} catch (Exception $e) {
echo "recordLog error";
}
}
public function onTask($server, $task_id, $from_id, $data)
{
switch ($data['type']){
case "change":
self::push_room($data['room'], $data);
break;
}
return true;
}
/**
* 监听关闭事件的回调
*/
public function onClose($ser, $fd)
{
//退出房间清除redis
$group = $this->redis->sMembers('group');
foreach ($group as $v) {
$fangjian = $this->redis->hgetall($v);
if(empty($fangjian)) continue;
foreach ($fangjian as $k => $vv) {
if ($fd == $vv) {
$this->redis->hdel($v, $k);
self::recordLog($vv, $k, $v, "close");
break 2;
}
}
}
}
具体代码大家可以参考上一篇文章swoole实现多对多群聊进阶篇,代码都是大同小异,这里可以看到,我没有让小弟去处理onclose事件了,因为测试中,线程不能调用swoole_mysql的事件,所以小弟还有有嫌疑的,这里就不先追究了,代码改完后运行,第一次链接,插入一条记录,间隔两小时后,第二次链接,发现可以实现功能效果!
完事收工!之前的代码出错的原因值得深入调查,但是目前还没有查到,大家知道的可以评论告诉一下下我(认真脸)