PHP常驻进程如何解决数据库连接被断开
目录
PHP常驻进程如何解决数据库连接被断开
常驻进程的数据库连接是启动时初始化的,然后就一直连着,MySQL 的配置中,有一个叫做 “wait_timeout"的参数,这个参数大致的意思是这样:当一个客户端连接到 MySQL 数据库后,如果客户端不自己断开,也不做任何操作,MySQL 数据库会将这个连接保留"wait_timeout” 这么长时间(单位是 s,默认是 28800s,也就是 8 小时),超过这个时间之后,MySQL 数据库为了节省资源,就会在数据库端断开这个连接;当然,在此过程中,如果客户端在这个连接上有任意的操作,MySQL 数据库都会重新开始计算这个时间。
所以,需要自己实现重连机制来确保程序继续进行。
我们以Laravel为例,它已经实现了自动重连的机制。
vendor\Illuminate\Database\Connection.php
中的run方法是最终执行sql的方法。
// 采用异常捕获的方式判断是否需要重连
protected function run($query, $bindings, Closure $callback)
{
$this->reconnectIfMissingConnection();
$start = microtime(true);
// Here we will run this query. If an exception occurs we'll determine if it was
// caused by a connection that has been lost. If that is the cause, we'll try
// to re-establish connection and re-run the query with a fresh connection.
try {
$result = $this->runQueryCallback($query, $bindings, $callback);
} catch (QueryException $e) {
$result = $this->handleQueryException(
$e, $query, $bindings, $callback
);
}
// Once we have run the query we will calculate the time that it took to run and
// then log the query, bindings, and execution time so we will report them on
// the event that the developer needs them. We'll log time in milliseconds.
$this->logQuery(
$query, $bindings, $this->getElapsedTime($start)
);
return $result;
}
// 判断传入的数据库连接是否有效
protected function reconnectIfMissingConnection()
{
if (is_null($this->pdo)) {
$this->reconnect();
}
}
// 重连
public function reconnect()
{
if (is_callable($this->reconnector)) {
return call_user_func($this->reconnector, $this);
}
throw new LogicException('Lost connection and no reconnector available.');
}
// 判断是连接断开导致的异常
// vendor\Illuminate\Database\DetectsLostConnections.php
protected function causedByLostConnection(Throwable $e)
{
$message = $e->getMessage();
return Str::contains($message, [
'server has gone away',
'no connection to the server',
'Lost connection',
'is dead or not enabled',
'Error while sending',
'decryption failed or bad record mac',
'server closed the connection unexpectedly',
'SSL connection has been closed unexpectedly',
'Error writing data to the connection',
'Resource deadlock avoided',
'Transaction() on null',
'child connection forced to terminate due to client_idle_limit',
'query_wait_timeout',
'reset by peer',
'Physical connection is not usable',
'TCP Provider: Error code 0x68',
'Name or service not known',
'ORA-03114',
]);
}