mysql断线重连_Yii2实现Mysql断线重连

本文介绍了在Yii2框架中处理MySQL断线重连的问题。通过创建一个自定义的SQL执行类,当捕获到特定的数据库连接错误时,关闭并重新打开数据库连接,从而实现断线后自动重连的功能,确保长连接服务的稳定性。
摘要由CSDN通过智能技术生成

缘由

大家都知道我们做一个客服系统,是基于websocket长连接服务的。在这些长连接服务进程中,会对数据库有些操作。建议尽量在这些长连接服务中,少查询数据,能用缓存都用缓存。我们都知道数据库服务保持连接是有时间限制的,过了时间在操作数据库会出现错误:MySQL server has gone away。这里就要用到数据库重连机制来实现了

我们的客服系统使用的MVC框架是Yii2,大家都知道我一直使用这个框架,其他的框架基本不怎么熟悉。那我们就看看基于Yii2 如何实现数据库断开重连机制

解决思路

在很多编程语言里面有一个概念:连接池。在世界上最好的语言php世界里目前这块成熟的还是比较少的,这个主要是php的以前的应用场景主要是web,都是短连接。在Java语言中数据库连接池会定期发送一些查询语句到数据库进行查询维护着数据库连接(由于个人Java水平有限,如有误请大家指正)。

基于上面的思想,借鉴前面的思想。由于连接池也是单独的独立服务,php不具备这样的条件,那我们改变下思路,在执行SQL报错进行数据库重新连接在执行一次就可以了。

实现过程

实现代码

如下图的上线一个SQL执行类,在出错的时候进行再次执行

handleException($e)){

return parent::execute();

}

throw $e;

}

}

/**

* 重新处理一下.

* @param string $method

* @param null $fetchMode

* @return mixed

* @throws Exception

*/

protected function queryInternal($method, $fetchMode = null)

{

try{

return parent::queryInternal($method, $fetchMode);

}catch(\Exception $e) {

if( $this->handleException($e) ){

return parent::queryInternal($method, $fetchMode);

}

throw $e;

}

}

/**

* 利用$this->retry属性,标记当前是否是数据库重连

* 重写bindPendingParams方法,当当前是数据库重连之后重试的时候

* 调用bindValues方法重新绑定一次参数.

*/

protected function bindPendingParams()

{

if ($this->retry) {

$this->retry = false;

$this->bindValues($this->params);

}

parent::bindPendingParams();

}

/**

* 处理执行sql时捕获的异常信息

* 并且根据异常信息来决定是否需要重新连接数据库

* SQL Error (2013): Lost connection to MySQL server at 'waiting for initial communication packet', system error: 0

* SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

* Error while sending QUERY packet. PID=24450 The SQL being executed was

* 但是实际使用中发现,由于Yii2对数据库异常进行了处理并封装成\yii\db\Exception异常

* 因此2006错误的错误码并不能在errorInfo中获取到,因此需要判断errorMsg内容

* @param \Exception $e

* @return bool true: 需要重新执行sql false: 不需要重新执行sql

*/

private function handleException(\Exception $e)

{

//如果不是yii\db\Exception异常抛出该异常或者不是MySQL server has gone away

$offset_1 = stripos($e->getMessage(),'MySQL server has gone away');

$offset_2 = stripos($e->getMessage(),'Lost connection to MySQL server');

$offset_3 = stripos($e->getMessage(),'Error while sending QUERY packet');

if( ( $e instanceof \yii\db\Exception) == true || ($offset_1 || $offset_2 || $offset_3 )){

$this->retry = true;

//将pdo设置从null

$this->pdoStatement = null;

$this->db->close();

$this->db->open();

return true;

}

return false;

}

}

配置更改

在数据库配置的地方更改 执行类为上面新写的,如下图示意'chat_db' => [

'class' => 'yii\db\Connection',

'dsn' => 'mysql:host=localhost;dbname=chat_db',

'username' => 'root',

'password' => '',

'charset' => 'utf8mb4',

'commandClass'  =>  'common\components\Command',//这一句是重点

],

最后

我们的客服系统已经平稳运行了差不多6个月了,期间长连接服务也是非常稳定的。撒花。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值