swoole实现多对多群聊(三)

博客作者在实现多对多群聊时遇到PDO连接在约一小时后失效的问题,导致无法向数据库插入数据但不报错。尝试PDO的持久连接设置未成功。经过排查,怀疑是子线程影响,但实际并非如此。最终,作者转向使用Swoole的异步MySQL客户端解决问题,实现了所需功能。现在,长时间连接问题已解决,但PDO失效的具体原因仍有待进一步调查。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这次来是因为上篇文章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的事件,所以小弟还有有嫌疑的,这里就不先追究了,代码改完后运行,第一次链接,插入一条记录,间隔两小时后,第二次链接,发现可以实现功能效果!
日志记录
完事收工!之前的代码出错的原因值得深入调查,但是目前还没有查到,大家知道的可以评论告诉一下下我(认真脸)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值