From 313f37a1870d26ca198d22af9f051175e9ec472e Mon Sep 17 00:00:00 2001 From: Andie Chang <7233960+andiechang@users.noreply.github.com> Date: Fri, 20 Aug 2021 17:28:50 +0800 Subject: [PATCH] Update Connection.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix this issue: https://github.com/swoft-cloud/swoft/issues/1365 MySQL setting: interactive_timeout = 60 wait_timeout = 60 swoft: db 使用讀寫分離設定 question: 生產環境大量連線時,會出現 MySQL server has gone away。 --- src/db/src/Connection/Connection.php | 66 +++++++++++++++++++++------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/src/db/src/Connection/Connection.php b/src/db/src/Connection/Connection.php index 47c860415..7ac0c225a 100644 --- a/src/db/src/Connection/Connection.php +++ b/src/db/src/Connection/Connection.php @@ -1,4 +1,4 @@ -pool = $pool; + $this->pool = $pool; $this->database = $database; $this->lastTime = time(); @@ -215,7 +214,7 @@ public function reconnect(): bool { try { switch ($this->pdoType) { - case self::TYPE_WRITE; + case self::TYPE_WRITE; $this->createPdo(); break; case self::TYPE_READ; @@ -533,12 +532,13 @@ public function statement(string $query, array $bindings = []): bool public function insertGetIdStatement(string $query, array $bindings = [], string $sequence = null): string { return $this->run($query, $bindings, function ($query, $bindings) use ($sequence) { - $statement = $this->getPdo()->prepare($query); + $pdo = $this->getPdo(); + $statement = $pdo->prepare($query); $this->bindValues($statement, $this->prepareBindings($bindings)); $statement->execute(); - return $this->getPdo()->lastInsertId($sequence); + return $pdo->lastInsertId($sequence); }); } @@ -580,7 +580,7 @@ public function affectingStatement(string $query, array $bindings = []): int */ public function unprepared(string $query): bool { - return (bool)$this->run($query, [], function ($query) { + return (bool) $this->run($query, [], function ($query) { return $this->getPdo()->exec($query); }); @@ -604,7 +604,7 @@ public function prepareBindings(array $bindings): array if ($value instanceof DateTimeInterface) { $bindings[$key] = $value->format($grammar->getDateFormat()); } elseif (is_bool($value)) { - $bindings[$key] = (int)$value; + $bindings[$key] = (int) $value; } } @@ -680,7 +680,7 @@ protected function runQueryCallback(string $query, array $bindings, Closure $cal $this->releaseOrRemove(); // Throw exception - throw new DbException($e->getMessage(), (int)$e->getCode(), $e); + throw new DbException($e->getMessage(), (int) $e->getCode(), $e); } // If an exception occurs when attempting to run a query, we'll format the error @@ -698,7 +698,7 @@ protected function runQueryCallback(string $query, array $bindings, Closure $cal CLog::error('Fail err=%s sql=%s', $e->getMessage(), $rawSql); // Throw exception - throw new DbException($e->getMessage(), (int)$e->getCode(), $e); + throw new DbException($e->getMessage(), (int) $e->getCode(), $e); } $this->pdoType = self::TYPE_DEFAULT; @@ -732,7 +732,7 @@ public function getRawSql(string $sql, array $bindings): string } elseif ($value === null) { $param = 'NULL'; } else { - $param = (string)$value; + $param = (string) $value; } $sql = StringHelper::replaceFirst($name, $param, $sql); @@ -741,7 +741,6 @@ public function getRawSql(string $sql, array $bindings): string return $sql; } - /** * Whether to reconnect * @@ -774,7 +773,7 @@ protected function reconnectIfMissingConnection(): void protected function prepared(PDOStatement $statement): PDOStatement { if (!$this->fetchMode) { - $config = $this->database->getConfig(); + $config = $this->database->getConfig(); $this->fetchMode = $config['fetchMode'] ?? self::DEFAULT_FETCH_MODE; } @@ -932,6 +931,12 @@ protected function getPdoForSelect($useReadPdo = true) public function getPdo(): PDO { $this->pdoType = self::TYPE_WRITE; + + // check pdo connection is alive or not + if (false === $this->pingPdo($this->pdo)) { + $this->reconnect(); + } + return $this->pdo; } @@ -952,9 +957,37 @@ public function getReadPdo(): PDO } $this->pdoType = self::TYPE_READ; + + // check pdo connection is alive or not + if (false === $this->pingPdo($this->readPdo)) { + $this->reconnect(); + } + return $this->readPdo; } + /** + * Check PDO connection is alive or not + * + * @param PDO $pdo + * @return boolean + */ + private function pingPdo(PDO $pdo): bool + { + try { + if (!is_object($pdo) || !method_exists($pdo, 'query')) { + return false; + } + + // do ping + $pdo->query('do 1'); + } catch (\Throwable $th) { + return false; + } + + return true; + } + /** * Bind values to their parameters in the given statement. * @@ -1063,7 +1096,6 @@ protected function getConMananger(): ConnectionManager return BeanFactory::getBean(ConnectionManager::class); } - /** * Create pdo * @@ -1072,7 +1104,7 @@ protected function getConMananger(): ConnectionManager private function createPdo() { $writes = $this->database->getWrites(); - $write = $writes[array_rand($writes)]; + $write = $writes[array_rand($writes)]; $dsn = $write['dsn']; $this->parseDbName($dsn); @@ -1128,7 +1160,7 @@ private function parseDbName(string $dns): void private function selectDb(PDO $pdo, string $dbname): void { $useStmt = sprintf('use %s', $dbname); - $result = $pdo->exec($useStmt); + $result = $pdo->exec($useStmt); if ($result !== false) { return; }