|
@@ -233,28 +233,41 @@ class Pdo extends Base
|
|
|
}
|
|
}
|
|
|
protected function withConnection($method, $sql, array $bind, callable $callback)
|
|
protected function withConnection($method, $sql, array $bind, callable $callback)
|
|
|
{
|
|
{
|
|
|
- $connection = null;
|
|
|
|
|
- $broken = false;
|
|
|
|
|
- try {
|
|
|
|
|
- $connection = $this->borrowConnection($method);
|
|
|
|
|
- $statement = $this->runStatement($connection, $sql, $bind);
|
|
|
|
|
- if (Dever::get(Debug::class)->shell) {
|
|
|
|
|
- $this->bsql($sql, $bind);
|
|
|
|
|
- $this->log(array('sql' => $sql, 'count' => $statement->rowCount()));
|
|
|
|
|
- }
|
|
|
|
|
- return $callback($connection, $statement);
|
|
|
|
|
- } catch (\RuntimeException $runtime) {
|
|
|
|
|
- if (!$connection) {
|
|
|
|
|
- Dever::out()->error($runtime->getMessage());
|
|
|
|
|
- }
|
|
|
|
|
- throw $runtime;
|
|
|
|
|
- } catch (\PDOException $exception) {
|
|
|
|
|
- $broken = true;
|
|
|
|
|
- $this->error(array('sql' => $sql, 'msg' => $exception->getMessage()));
|
|
|
|
|
- } finally {
|
|
|
|
|
- if ($connection) {
|
|
|
|
|
- $this->recycleConnection($method, $connection, $broken);
|
|
|
|
|
|
|
+ $attempts = 0;
|
|
|
|
|
+ while (true) {
|
|
|
|
|
+ $connection = null;
|
|
|
|
|
+ $broken = false;
|
|
|
|
|
+ try {
|
|
|
|
|
+ $connection = $this->borrowConnection($method);
|
|
|
|
|
+ $statement = $this->runStatement($connection, $sql, $bind);
|
|
|
|
|
+ if (Dever::get(Debug::class)->shell) {
|
|
|
|
|
+ $this->bsql($sql, $bind);
|
|
|
|
|
+ $this->log(array('sql' => $sql, 'count' => $statement->rowCount()));
|
|
|
|
|
+ }
|
|
|
|
|
+ return $callback($connection, $statement);
|
|
|
|
|
+ } catch (\RuntimeException $runtime) {
|
|
|
|
|
+ if (!$connection) {
|
|
|
|
|
+ Dever::out()->error($runtime->getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ throw $runtime;
|
|
|
|
|
+ } catch (\PDOException $exception) {
|
|
|
|
|
+ $broken = $this->isDisconnectException($exception);
|
|
|
|
|
+ if (!$broken || $attempts >= 1) {
|
|
|
|
|
+ $this->error(array('sql' => $sql, 'msg' => $exception->getMessage()));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $attempts++;
|
|
|
|
|
+ if ($connection) {
|
|
|
|
|
+ $this->recycleConnection($method, $connection, true);
|
|
|
|
|
+ $connection = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if ($connection) {
|
|
|
|
|
+ $this->recycleConnection($method, $connection, $broken);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
protected function runStatement($connection, $sql, array $bind)
|
|
protected function runStatement($connection, $sql, array $bind)
|
|
@@ -295,4 +308,15 @@ class Pdo extends Base
|
|
|
}
|
|
}
|
|
|
parent::releaseConnection($method, $connection, $broken);
|
|
parent::releaseConnection($method, $connection, $broken);
|
|
|
}
|
|
}
|
|
|
|
|
+ protected function isDisconnectException(\PDOException $exception): bool
|
|
|
|
|
+ {
|
|
|
|
|
+ $code = (int) $exception->getCode();
|
|
|
|
|
+ if (in_array($code, [2006, 2013, 2055], true)) {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ $message = strtolower($exception->getMessage());
|
|
|
|
|
+ return str_contains($message, 'server has gone away') ||
|
|
|
|
|
+ str_contains($message, 'no connection to the server') ||
|
|
|
|
|
+ str_contains($message, 'lost connection');
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|