From 2e1297f8afd24782072656ed75d82bb21fd74f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mr=C2=B7x?= Date: Mon, 16 Aug 2021 18:10:50 +0800 Subject: [PATCH] e --- src/Affair/BeginTransaction.php | 8 + src/Affair/Commit.php | 10 ++ src/Affair/Rollback.php | 8 + src/Command.php | 127 +++------------- src/Connection.php | 9 +- src/Mysql/PDO.php | 250 ++++++++++++++++++++++++++++++++ 6 files changed, 297 insertions(+), 115 deletions(-) create mode 100644 src/Affair/BeginTransaction.php create mode 100644 src/Affair/Commit.php create mode 100644 src/Affair/Rollback.php create mode 100644 src/Mysql/PDO.php diff --git a/src/Affair/BeginTransaction.php b/src/Affair/BeginTransaction.php new file mode 100644 index 0000000..bc78819 --- /dev/null +++ b/src/Affair/BeginTransaction.php @@ -0,0 +1,8 @@ +prepare()) == false) { - return false; - } + $pdo = $this->db->getConnect($this->sql); if ($type === static::FETCH_COLUMN) { - $data = $prepare->fetchAll(PDO::FETCH_ASSOC); + $data = $pdo->fetchColumn($this->sql, $this->params); } else if ($type === static::ROW_COUNT) { - $data = $prepare->rowCount(); + $data = $pdo->count($this->sql, $this->params); } else if ($type === static::FETCH_ALL) { - $data = $prepare->fetchAll(PDO::FETCH_ASSOC); + $data = $pdo->fetchAll($this->sql, $this->params); } else { - $data = $prepare->fetch(PDO::FETCH_ASSOC); + $data = $pdo->fetch($this->sql, $this->params); } - $prepare->closeCursor(); return $data; } @@ -169,106 +163,19 @@ class Command extends Component /** * @param $isInsert * @param $hasAutoIncrement - * @return bool|string|int + * @return bool|int * @throws Exception */ - private function insert_or_change($isInsert, $hasAutoIncrement): bool|string|int + private function insert_or_change($isInsert, $hasAutoIncrement): bool|int { - if (($result = $this->getPdoStatement()) === false) { - return $result; + $pdo = $this->db->getConnect($this->sql); + $result = $pdo->execute($this->sql, $this->params); + if (($hasAutoIncrement || !$isInsert) && $result == 0){ + return false; } - if ($isInsert === false || !$hasAutoIncrement) { - return true; - } - if ($result == 0 && $hasAutoIncrement->isAutoIncrement()) { - return $this->addError(static::DB_ERROR_MESSAGE, 'mysql'); - } - return $result == 0 ? true : $result; - } - - - /** - * 重新构建 - * @throws - */ - private function getPdoStatement(): bool|int - { - if (empty($this->sql)) { - return $this->addError('no sql.', 'mysql'); - } - if (!(($connect = $this->db->getConnect($this->sql)) instanceof PDO)) { - return $this->addError('get client error.', 'mysql'); - } - if (!(($prepare = $connect->prepare($this->sql)) instanceof PDOStatement)) { - return $this->addError($this->errorMessage($prepare), 'mysql'); - } - $result = $this->checkResponse($prepare, $connect); - $prepare->closeCursor(); return $result; } - - /** - * @param $prepare - * @return string - */ - private function errorMessage($prepare): string - { - return $this->sql . ':' . ($prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE); - } - - - /** - * @return bool|\PDOStatement - * @throws \Exception - */ - private function prepare(): bool|PDOStatement - { - if (!(($connect = $this->db->getConnect($this->sql)) instanceof PDO)) { - return $this->addError('get client error.', 'mysql'); - } - if (!(($prepare = $connect->query($this->sql)) instanceof PDOStatement)) { - $error = $prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE; - return $this->addError($this->sql . ':' . $error, 'mysql'); - } - return $prepare; - } - - - /** - * @param $prepare - * @param $connect - * @return bool|int - * @throws \Exception - */ - private function checkResponse($prepare, $connect): bool|int - { - $result = $prepare->execute($this->params); - if ($result === false) { - return $this->addError($connect->errorInfo()[2], 'mysql'); - } - return (int)$connect->lastInsertId(); - } - - - /** - * @param $modelName - * @return $this - */ - public function setModelName($modelName): static - { - $this->_modelName = $modelName; - return $this; - } - - /** - * @return string - */ - public function getModelName(): string - { - return $this->_modelName; - } - /** * @return int|bool|array|string|null * @throws Exception diff --git a/src/Connection.php b/src/Connection.php index 0f695ad..504cd98 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -12,22 +12,21 @@ namespace Database; use Annotation\Inject; -use Database\Affair\BeginTransaction; -use Database\Affair\Commit; -use Database\Affair\Rollback; use Database\Mysql\Schema; use Exception; use JetBrains\PhpStorm\Pure; -use PDO; +use Database\Mysql\PDO; use ReflectionException; use Server\Events\OnWorkerExit; use Server\Events\OnWorkerStop; use Kiri\Abstracts\Component; use Kiri\Abstracts\Config; -use Kiri\Event; use Kiri\Events\EventProvider; use Kiri\Exception\NotFindClassException; use Kiri\Kiri; +use Database\Affair\BeginTransaction; +use Database\Affair\Commit; +use Database\Affair\Rollback; /** * Class Connection diff --git a/src/Mysql/PDO.php b/src/Mysql/PDO.php new file mode 100644 index 0000000..2630d11 --- /dev/null +++ b/src/Mysql/PDO.php @@ -0,0 +1,250 @@ +heartbeat_check(); + } + + + /** + * @return bool + */ + public function inTransaction(): bool + { + return $this->_transaction > 0; + } + + + /** + * + */ + public function heartbeat_check(): void + { + if ($this->_timer === -1 && Context::inCoroutine()) { + $this->_timer = Timer::tick(3000, function () { + try { + if (time() - $this->_last > 10 * 60) { + $this->stopHeartbeatCheck(); + } + if (!$this->pdo->getAttribute(\PDO::ATTR_SERVER_INFO)) { + $this->stopHeartbeatCheck(); + } + } catch (\Throwable $throwable) { + error($throwable); + } + }); + } + } + + + /** + * + */ + public function stopHeartbeatCheck(): void + { + $this->pdo = null; + if (Context::inCoroutine()) { + Timer::clear($this->_timer); + } + $this->_timer = -1; + } + + + /** + * + */ + public function beginTransaction() + { + if ($this->_transaction == 0) { + $this->pdo->beginTransaction(); + } + $this->_transaction++; + } + + + /** + * + */ + public function commit() + { + if ($this->_transaction == 0) { + $this->pdo->commit(); + } + $this->_transaction--; + } + + + /** + * + */ + public function rollback() + { + if ($this->_transaction == 0) { + $this->pdo->rollBack(); + } + $this->_transaction--; + } + + + /** + * @param string $sql + * @param array $params + * @return array + * @throws Exception + */ + public function fetchAll(string $sql, array $params = []): array + { + return $this->queryPrev($sql, $params)->fetchAll(\PDO::FETCH_ASSOC); + } + + + /** + * @param string $sql + * @param array $params + * @return array + * @throws Exception + */ + public function fetch(string $sql, array $params = []): array + { + return $this->queryPrev($sql, $params)->fetch(\PDO::FETCH_ASSOC); + } + + + /** + * @param string $sql + * @param array $params + * @return array + * @throws Exception + */ + public function fetchColumn(string $sql, array $params = []): array + { + return $this->queryPrev($sql, $params)->fetchColumn(\PDO::FETCH_ASSOC); + } + + + /** + * @param string $sql + * @param array $params + * @return int + * @throws Exception + */ + public function count(string $sql, array $params = []): int + { + return $this->queryPrev($sql, $params)->rowCount(); + } + + + /** + * @param string $sql + * @param array $params + * @return PDOStatement + * @throws Exception + */ + private function queryPrev(string $sql, array $params = []): PDOStatement + { + $this->_last = time(); + if (($statement = $this->pdo->query($sql)) === false) { + throw new Exception($this->pdo->errorInfo()[1]); + } + return $this->bindValue($statement, $params); + } + + + /** + * @param PDOStatement $statement + * @param array $params + * @return PDOStatement + */ + private function bindValue(PDOStatement $statement, array $params = []): PDOStatement + { + if (empty($params)) return $statement; + foreach ($params as $key => $param) { + $statement->bindValue($key, $param); + } + return $statement; + } + + + /** + * @param string $sql + * @param array $params + * @return int + * @throws Exception + */ + public function execute(string $sql, array $params = []): int + { + $this->_last = time(); + if (!(($prepare = $this->pdo->prepare($sql)) instanceof PDOStatement)) { + throw new Exception($prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE); + } + defer(fn() => $prepare->closeCursor()); + if ($prepare->execute($params) === false) { + throw new Exception($prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE); + } + return (int)$this->pdo->lastInsertId(); + } + + + /** + * @return \PDO + */ + public function getPdo(): \PDO + { + if (!($this->pdo instanceof \PDO)) { + $this->pdo = $this->newClient(); + } + return $this->pdo; + } + + + /** + * @return \PDO + */ + private function newClient(): \PDO + { + $link = new \PDO('mysql:dbname=' . $this->dbname . ';host=' . $this->cds, $this->username, $this->password, [ + \PDO::ATTR_EMULATE_PREPARES => false, + \PDO::ATTR_CASE => \PDO::CASE_NATURAL, + \PDO::ATTR_TIMEOUT => 60, + \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, + \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . $this->chatset + ]); + $link->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + $link->setAttribute(\PDO::ATTR_STRINGIFY_FETCHES, false); + $link->setAttribute(\PDO::ATTR_ORACLE_NULLS, \PDO::NULL_EMPTY_STRING); + return $link; + } + +}