Skip to content

Commit

Permalink
优化数据库操作判断断线错误码,自动关闭连接 (#244)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yurunsoft authored Jan 7, 2022
1 parent 0c2ee24 commit b5a8874
Show file tree
Hide file tree
Showing 7 changed files with 261 additions and 56 deletions.
4 changes: 4 additions & 0 deletions src/Db/Contract/IPgsqlDb.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@

interface IPgsqlDb extends IDb
{
/**
* 检查错误码是否为掉线
*/
public function checkCodeIsOffline(string $code): bool;
}
174 changes: 147 additions & 27 deletions src/Db/Drivers/PdoPgsql/Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use Imi\Db\Exception\DbException;
use Imi\Db\Statement\StatementManager;
use Imi\Db\Transaction\Transaction;
use Imi\Pgsql\Db\Contract\IPgsqlDb;
use Imi\Pgsql\Db\Contract\IPgsqlStatement;
use Imi\Pgsql\Db\PgsqlBase;
use Imi\Pgsql\Db\Util\SqlUtil;
Expand All @@ -21,7 +20,7 @@
*
* @Bean("PdoPgsqlDriver")
*/
class Driver extends PgsqlBase implements IPgsqlDb
class Driver extends PgsqlBase
{
/**
* 连接对象
Expand Down Expand Up @@ -104,14 +103,30 @@ public function isConnected(): bool
*/
public function ping(): bool
{
$instance = $this->instance;
if (!$instance)
{
return false;
}
try
{
$instance = $this->instance;
if ($instance->query('select 1'))
{
return true;
}
if ($this->checkCodeIsOffline($instance->errorInfo()[0] ?? ''))
{
$this->close();
}

return $instance && false !== $instance->query('select 1');
return false;
}
catch (\Throwable $e)
catch (\PDOException $e)
{
if ($this->checkCodeIsOffline($e->errorInfo[0]))
{
$this->close();
}
}

return false;
Expand Down Expand Up @@ -140,12 +155,13 @@ public function close(): void
$this->lastStmt = null;
}
$this->instance = null;
$this->transaction->init();
}

/**
* {@inheritDoc}
*/
public function getInstance(): PDO
public function getInstance(): ?PDO
{
return $this->instance;
}
Expand All @@ -155,12 +171,28 @@ public function getInstance(): PDO
*/
public function beginTransaction(): bool
{
if (!$this->inTransaction() && !$this->instance->beginTransaction())
try
{
return false;
if (!$this->inTransaction() && !$this->instance->beginTransaction())
{
if ($this->checkCodeIsOffline($this->instance->errorInfo()[0] ?? ''))
{
$this->close();
}

return false;
}
$this->exec('SAVEPOINT P' . $this->getTransactionLevels());
$this->transaction->beginTransaction();
}
catch (\PDOException $e)
{
if ($this->checkCodeIsOffline($e->errorInfo[0]))
{
$this->close();
}
throw $e;
}
$this->exec('SAVEPOINT P' . $this->getTransactionLevels());
$this->transaction->beginTransaction();

return true;
}
Expand All @@ -170,7 +202,28 @@ public function beginTransaction(): bool
*/
public function commit(): bool
{
return $this->instance->commit() && $this->transaction->commit();
try
{
if (!$this->instance->commit())
{
if ($this->checkCodeIsOffline($this->instance->errorInfo()[0] ?? ''))
{
$this->close();
}

return false;
}
}
catch (\PDOException $e)
{
if ($this->checkCodeIsOffline($e->errorInfo[0]))
{
$this->close();
}
throw $e;
}

return $this->transaction->commit();
}

/**
Expand All @@ -180,7 +233,18 @@ public function rollBack(?int $levels = null): bool
{
if (null === $levels)
{
$result = $this->instance->rollback();
try
{
$result = $this->instance->rollback();
}
catch (\PDOException $e)
{
if ($this->checkCodeIsOffline($e->errorInfo[0]))
{
$this->close();
}
throw $e;
}
}
else
{
Expand All @@ -191,6 +255,10 @@ public function rollBack(?int $levels = null): bool
{
$this->transaction->rollBack($levels);
}
elseif ($this->checkCodeIsOffline($this->instance->errorInfo()[0] ?? ''))
{
$this->close();
}

return $result;
}
Expand Down Expand Up @@ -261,11 +329,29 @@ public function lastSql(): string
public function exec(string $sql): int
{
$this->lastSql = $sql;
$this->lastStmt = null;

$result = $this->instance->exec($sql);
if (false === $result)
try
{
throw new DbException('SQL prepare error [' . $this->errorCode() . '] ' . $this->errorInfo() . \PHP_EOL . 'sql: ' . $sql . \PHP_EOL);
$result = $this->instance->exec($sql);
if (false === $result)
{
$errorCode = $this->errorCode();
$errorInfo = $this->errorInfo();
if ($this->checkCodeIsOffline($this->instance->errorInfo()[0] ?? ''))
{
$this->close();
}
throw new DbException('SQL exec error [' . $errorCode . '] ' . $errorInfo . \PHP_EOL . 'sql: ' . $sql . \PHP_EOL);
}
}
catch (\PDOException $e)
{
if ($this->checkCodeIsOffline($e->errorInfo[0]))
{
$this->close();
}
throw $e;
}

return $result;
Expand Down Expand Up @@ -330,17 +416,34 @@ public function prepare(string $sql, array $driverOptions = []): IPgsqlStatement
}
else
{
$this->lastSql = $sql;
$lastStmt = $this->lastStmt = $this->instance->prepare($sql, $driverOptions);
// @phpstan-ignore-next-line
if (false === $lastStmt)
try
{
throw new DbException('SQL prepare error [' . $this->errorCode() . '] ' . $this->errorInfo() . \PHP_EOL . 'sql: ' . $sql . \PHP_EOL);
$this->lastSql = $sql;
$lastStmt = $this->lastStmt = $this->instance->prepare($sql, $driverOptions);
// @phpstan-ignore-next-line
if (false === $lastStmt)
{
$errorCode = $this->errorCode();
$errorInfo = $this->errorInfo();
if ($this->checkCodeIsOffline($this->instance->errorInfo()[0] ?? ''))
{
$this->close();
}
throw new DbException('SQL prepare error [' . $errorCode . '] ' . $errorInfo . \PHP_EOL . 'sql: ' . $sql . \PHP_EOL);
}
$stmt = App::getBean(Statement::class, $this, $lastStmt);
if ($this->isCacheStatement && !isset($stmtCache))
{
StatementManager::setNX($stmt, true);
}
}
$stmt = App::getBean(Statement::class, $this, $lastStmt);
if ($this->isCacheStatement && !isset($stmtCache))
catch (\PDOException $e)
{
StatementManager::setNX($stmt, true);
if ($this->checkCodeIsOffline($e->errorInfo[0]))
{
$this->close();
}
throw $e;
}
}

Expand All @@ -352,11 +455,28 @@ public function prepare(string $sql, array $driverOptions = []): IPgsqlStatement
*/
public function query(string $sql): IPgsqlStatement
{
$this->lastSql = $sql;
$this->lastStmt = $lastStmt = $this->instance->query($sql);
if (false === $lastStmt)
try
{
throw new DbException('SQL query error: [' . $this->errorCode() . '] ' . $this->errorInfo() . \PHP_EOL . 'sql: ' . $sql . \PHP_EOL);
$this->lastSql = $sql;
$this->lastStmt = $lastStmt = $this->instance->query($sql);
if (false === $lastStmt)
{
$errorCode = $this->errorCode();
$errorInfo = $this->errorInfo();
if ($this->checkCodeIsOffline($this->instance->errorInfo()[0] ?? ''))
{
$this->close();
}
throw new DbException('SQL query error [' . $errorCode . '] ' . $errorInfo . \PHP_EOL . 'sql: ' . $sql . \PHP_EOL);
}
}
catch (\PDOException $e)
{
if ($this->checkCodeIsOffline($e->errorInfo[0]))
{
$this->close();
}
throw $e;
}

return App::getBean(Statement::class, $this, $lastStmt);
Expand Down
41 changes: 29 additions & 12 deletions src/Db/Drivers/PdoPgsql/Statement.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,28 +128,45 @@ public function getSql(): string
*/
public function execute(array $inputParameters = null): bool
{
$statement = $this->statement;
$statement->closeCursor();
if ($inputParameters)
try
{
foreach ($inputParameters as $k => $v)
$statement = $this->statement;
$statement->closeCursor();
if ($inputParameters)
{
if (is_numeric($k))
foreach ($inputParameters as $k => $v)
{
$statement->bindValue($k + 1, $v, $this->getDataTypeByValue($v));
if (is_numeric($k))
{
$statement->bindValue($k + 1, $v, $this->getDataTypeByValue($v));
}
else
{
$statement->bindValue($k, $v, $this->getDataTypeByValue($v));
}
}
else
}
$result = $statement->execute();
if (!$result)
{
$errorCode = $this->errorCode();
$errorInfo = $this->errorInfo();
if ($this->db->checkCodeIsOffline($this->db->errorInfo()[0] ?? ''))
{
$statement->bindValue($k, $v, $this->getDataTypeByValue($v));
$this->db->close();
}
throw new DbException('SQL query error [' . $errorCode . '] ' . $errorInfo . \PHP_EOL . 'sql: ' . $this->getSql() . \PHP_EOL);
}
$this->updateLastInsertId();
}
$result = $statement->execute();
if (!$result)
catch (\PDOException $e)
{
throw new DbException('SQL query error: [' . $this->errorCode() . '] ' . $this->errorInfo() . ' sql: ' . $this->getSql());
if ($this->db->checkCodeIsOffline($e->errorInfo[0]))
{
$this->db->close();
}
throw $e;
}
$this->updateLastInsertId();

return $result;
}
Expand Down
Loading

0 comments on commit b5a8874

Please sign in to comment.