一 安装及配置
composer require hyperf/db
php bin/hyperf.php vendor:publish hyperf/db
默认配置 config/autoload/db.php
如下,数据库支持多库配置,默认为 default
。
配置项 | 类型 | 默认值 | 备注 |
---|---|---|---|
driver | string | 无 | 数据库引擎 支持 pdo 和 mysql |
host | string | localhost | 数据库地址 |
port | int | 3306 | 数据库地址 |
database | string | 无 | 数据库默认 DB |
username | string | 无 | 数据库用户名 |
password | string | null | 数据库密码 |
charset | string | utf8 | 数据库编码 |
collation | string | utf8_unicode_ci | 数据库编码 |
fetch_mode | int | PDO::FETCH_ASSOC | PDO 查询结果集类型 |
pool.min_connections | int | 1 | 连接池内最少连接数 |
pool.max_connections | int | 10 | 连接池内最大连接数 |
pool.connect_timeout | float | 10.0 | 连接等待超时时间 |
pool.wait_timeout | float | 3.0 | 超时时间 |
pool.heartbeat | int | -1 | 心跳 |
pool.max_idle_time | float | 60.0 | 最大闲置时间 |
options | array | PDO 配置 |
具体接口可以查看 Hyperf\DB\ConnectionInterface
。
方法名 | 返回值类型 | 备注 |
---|---|---|
beginTransaction | void | 开启事务 支持事务嵌套 |
commit | void | 提交事务 支持事务嵌套 |
rollBack | void | 回滚事务 支持事务嵌套 |
insert | int | 插入数据,返回主键 ID,非自增主键返回 0 |
execute | int | 执行 SQL,返回受影响的行数 |
query | array | 查询 SQL,返回结果集列表 |
fetch | array, object | 查询 SQL,返回结果集的首行数据 |
connection | self | 指定连接的数据库 |
二 使用
#使用 DB 实例
use Hyperf\Context\ApplicationContext;
use Hyperf\DB\DB;$db = ApplicationContext::getContainer()->get(DB::class);$res = $db->query('SELECT * FROM `user` WHERE gender = ?;', [1]);#使用静态方法
use Hyperf\DB\DB;$res = DB::query('SELECT * FROM `user` WHERE gender = ?;', [1]);#使用匿名函数自定义方法
#此种方式可以允许用户直接操作底层的 PDO 或者 MySQL,所以需要自己处理兼容问题
use Hyperf\DB\DB;$sql = 'SELECT * FROM `user` WHERE id = ?;';
$bindings = [2];
$mode = \PDO::FETCH_OBJ;
$res = DB::run(function (\PDO $pdo) use ($sql, $bindings, $mode) {$statement = $pdo->prepare($sql);$this->bindValues($statement, $bindings);$statement->execute();return $statement->fetchAll($mode);
});
三 测试
use Hyperf\DB\DB as AustereDb;
use Hyperf\Utils\ApplicationContext;public function testdb1() {$db = ApplicationContext::getContainer()->get(AustereDb::class);$res = $db->query('SELECT * FROM `push_recode` WHERE id = ?;', [1]);var_dump($res);$res = AustereDb::query('SELECT * FROM `push_recode` WHERE id = ?;', [1]);var_dump($res);$sql = 'SELECT * FROM `push_recode` WHERE id = ?;';$bindings = [1];$mode = \PDO::FETCH_NUM;$res = AustereDb::run(function (\PDO $pdo) use ($sql, $bindings, $mode) {$statement = $pdo->prepare($sql);$this->bindValues($statement, $bindings);$statement->execute();return $statement->fetchAll($mode);});var_dump($res);
}
测试结果
array(1) {[0]=>array(4) {["id"]=>int(1)["is_push"]=>int(1)["push_time"]=>string(19) "2024-04-11 08:10:13"["created_at"]=>NULL}
}
array(1) {[0]=>array(4) {["id"]=>int(1)["is_push"]=>int(1)["push_time"]=>string(19) "2024-04-11 08:10:13"["created_at"]=>NULL}
}
array(1) {[0]=>array(4) {[0]=>int(1)[1]=>int(1)[2]=>string(19) "2024-04-11 08:10:13"[3]=>NULL}
}
可能由于版本问题,Hyperf\Context\ApplicationContext类不存在,所以使用Hyperf\Utils\ApplicationContext。
使用三种方法查询数据,使用DB实例、使用静态方法、使用PDO。
四 原理
获取容器参考hyperf console 执行-CSDN博客。
数据库配置获取参考hyperf console 执行-CSDN博客
用 php bin/hyperf.php vendor:publish hyperf/db 创建配置文件config\autoload\db.php后,其中使用.env文件。所以若项目数据库在.env中设置,配置文件可以不用改。
使用静态方法也是先获取容器,再调用对应方法。
使用run方法是根据配置文件获取数据库连接驱动,获取对应链接,默认是pdo。
若驱动为mysql,实际运行Hyperf\DB\MySQLConnection::run(Closure $closure)。
Closure类为一个闭包。
五 源码
#config\autoload\db.php
return ['default' => ['driver' => 'pdo','host' => env('DB_HOST', 'localhost'),'port' => env('DB_PORT', 3306),'database' => env('DB_DATABASE', 'hyperf'),'username' => env('DB_USERNAME', 'root'),'password' => env('DB_PASSWORD', ''),'charset' => env('DB_CHARSET', 'utf8mb4'),'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),'fetch_mode' => PDO::FETCH_ASSOC,'pool' => ['min_connections' => 1,'max_connections' => 10,'connect_timeout' => 10.0,'wait_timeout' => 3.0,'heartbeat' => -1,'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),],'options' => [PDO::ATTR_CASE => PDO::CASE_NATURAL,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,PDO::ATTR_STRINGIFY_FETCHES => false,PDO::ATTR_EMULATE_PREPARES => false,],],
];
#Hyperf\DB\DBprotected $poolName;public function __construct(PoolFactory $factory, string $poolName = 'default'){$this->factory = $factory;$this->poolName = $poolName;}public static function __callStatic($name, $arguments){$container = ApplicationContext::getContainer();$db = $container->get(static::class);return $db->{$name}(...$arguments);}public function __call($name, $arguments){$hasContextConnection = Context::has($this->getContextKey());$connection = $this->getConnection($hasContextConnection);try {$connection = $connection->getConnection();$result = $connection->{$name}(...$arguments);} catch (Throwable $exception) {$result = $connection->retry($exception, $name, $arguments);} finally {if (! $hasContextConnection) {if ($this->shouldUseSameConnection($name)) {// Should storage the connection to coroutine context, then use defer() to release the connection.Context::set($contextKey = $this->getContextKey(), $connection);defer(function () use ($connection, $contextKey) {Context::set($contextKey, null);$connection->release();});} else {// Release the connection after command executed.$connection->release();}}}return $result;}private function getContextKey(): string{return sprintf('db.connection.%s', $this->poolName);}protected function getConnection(bool $hasContextConnection): AbstractConnection{$connection = null;if ($hasContextConnection) {$connection = Context::get($this->getContextKey());}if (! $connection instanceof AbstractConnection) {$pool = $this->factory->getPool($this->poolName);$connection = $pool->get();}return $connection;}
#Hyperf\DB\Pool\PoolFactoryprotected $container;public function __construct(ContainerInterface $container){$this->container = $container;}public function getPool(string $name){if (isset($this->pools[$name])) {return $this->pools[$name];}$config = $this->container->get(ConfigInterface::class);$driver = $config->get(sprintf('db.%s.driver', $name), 'pdo');$class = $this->getPoolName($driver);$pool = make($class, [$this->container, $name]);if (! $pool instanceof Pool) {throw new InvalidDriverException(sprintf('Driver %s is not invalid.', $driver));}return $this->pools[$name] = $pool;}protected function getPoolName(string $driver){switch (strtolower($driver)) {case 'mysql':return MySQLPool::class;case 'pdo':return PDOPool::class;}if (class_exists($driver)) {return $driver;}throw new DriverNotFoundException(sprintf('Driver %s is not found.', $driver));}
#Hyperf\DB\Pool\MySQLPoolprotected function createConnection(): ConnectionInterface{return new MySQLConnection($this->container, $this, $this->config);}