lzpeng/hyperf-cycle

Cycle ORM support for hyperf

Maintainers

👁 liuzhanpeng

Package info

github.com/liuzhanpeng/hyperf-cycle

pkg:composer/lzpeng/hyperf-cycle

Statistics

Installs: 1 239

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.9 2026-04-19 02:26 UTC

Requires

Requires (Dev)

Suggests

None

Provides

None

Conflicts

None

Replaces

None

MIT 12e7d0fa3cd3211614d2c65bdfd7a6d0ac0c7002

  • liuzhanpeng <liuzhanpeng.woop@gmail.com>

This package is auto-updated.

Last update: 2026-06-19 02:49:09 UTC


README

Cycle ORM 在 Hyperf 中的连接池支持。

该库基于 hyperf/pool 为 Cycle ORM 提供协程安全的数据库连接复用能力,同时尽量保持与原生 Cycle ORM 一致的配置和使用方式。

特性

  • 基于 hyperf/pool 的数据库连接池
  • 按协程隔离 DatabaseORM 实例
  • 自动回收连接,减少长驻进程中的连接泄露风险
  • 保持与 Cycle ORM 接近的配置结构
  • 支持 MySQL、PostgreSQL、SQLite、SQL Server

安装

composer require lzpeng/hyperf-cycle

发布配置

安装后可发布默认配置:

php bin/hyperf.php vendor:publish lzpeng/hyperf-cycle

发布后会生成数据库配置文件,你可以在其中维护连接信息和连接池参数。

配置示例

<?php

declare(strict_types=1);

use Cycle\Database\Config\MySQL\TcpConnectionConfig;
use Lzpeng\HyperfCycle\Config\MySQLDriverConfig;
use function Hyperf\Support\env;

return [
 'default' => 'default',
 'databases' => [
 'default' => ['connection' => 'default'],
 ],
 'connections' => [
 'default' => new MySQLDriverConfig(
 connection: new TcpConnectionConfig(
 database: env('DB_DATABASE', 'test'),
 host: env('DB_HOST', 'localhost'),
 port: env('DB_PORT', 3306),
 user: env('DB_USER', 'test'),
 password: env('DB_PASSWORD', ''),
 charset: env('DB_CHARSET', 'utf8mb4'),
 ),
 reconnect: true,
 queryCache: true,
 options: [],
 poolOptions: [
 'min_connections' => env('DB_MIN_CONNECTIONS', 1),
 'max_connections' => env('DB_MAX_CONNECTIONS', 10),
 'connect_timeout' => env('DB_CONNECT_TIMEOUT', 10.0),
 'wait_timeout' => env('DB_WAIT_TIMEOUT', 3.0),
 'heartbeat' => env('DB_HEARTBEAT', -1),
 'max_idle_time' => env('DB_MAX_IDLE_TIME', 60.0),
 ],
 ),
 ],
];

连接池参数

参数 说明
min_connections 最小连接数
max_connections 最大连接数
connect_timeout 建立连接超时时间
wait_timeout 从连接池获取连接的等待时间
heartbeat 心跳检测间隔
max_idle_time 连接最大空闲时间

使用方式

推荐:从容器获取

该库通过 ConfigProvider 注册了 DatabaseManagerORMFactory,通常直接从容器取用即可:

use Lzpeng\HyperfCycle\ORMFactory;

$ormFactory = $container->get(ORMFactory::class);

$orm = $ormFactory->orm();
$em = $ormFactory->entityManager();

手动创建

use Cycle\Database\Config\MySQL\TcpConnectionConfig;
use Cycle\ORM\Entity\Behavior\EventDrivenCommandGenerator;
use Cycle\ORM\Schema;
use Lzpeng\HyperfCycle\Config\DatabaseConfig;
use Lzpeng\HyperfCycle\Config\MySQLDriverConfig;
use Lzpeng\HyperfCycle\DatabaseManager;
use Lzpeng\HyperfCycle\ORMFactory;

$databaseManager = new DatabaseManager(
 new DatabaseConfig([
 'default' => 'default',
 'databases' => [
 'default' => ['connection' => 'mysql'],
 ],
 'connections' => [
 'mysql' => new MySQLDriverConfig(
 connection: new TcpConnectionConfig(
 database: 'spiral',
 host: '127.0.0.1',
 port: 3306,
 user: 'spiral',
 password: '',
 ),
 queryCache: true,
 poolOptions: [
 'min_connections' => 1,
 'max_connections' => 20,
 'connect_timeout' => 10.0,
 'wait_timeout' => 3.0,
 'heartbeat' => -1,
 'max_idle_time' => 60.0,
 ],
 ),
 ],
 ])
);

$container = /** 获取容器 */;
$schemaConfig = /** Cycle Schema 配置 */;

$schema = new Schema($schemaConfig);
$commandGenerator = new EventDrivenCommandGenerator($schema, $container);

$ormFactory = new ORMFactory(
 databaseManager: $databaseManager,
 schema: $schema,
 commandGenerator: $commandGenerator,
);

$orm = $ormFactory->orm();
$em = $ormFactory->entityManager();

说明

  • 本库主要解决 Hyperf 场景下的 Cycle ORM 连接池与协程隔离问题。
  • 实体映射、Schema、Repository 等能力仍遵循标准 Cycle ORM 用法。
  • 数据库连接会在协程生命周期结束时自动释放。

注意事项

由于hyperf是一个长驻进程框架,连接对象不要作为对象类的属性进行持久化,否则会导致连接泄露问题或事务问题。建议在需要使用数据库连接的地方通过容器获取 DatabaseManagerORMFactory 来获取连接实例,确保连接能够正确回收。

错误使用示例:

use Cycle\Database\DatabaseInterface;
use Lzpeng\HyperfCycle\DatabaseManager;

/**
 * 产品数量管理器.
 */
class QuantityManager implements QuantityManagerInterface
{
 private DatabaseInterface $database;

 public function __construct(private DatabaseManager $databaseManager)
 {
 // 错误:作为属性持久化数据库连接会导致连接泄露问题或事务问题
 $this->database = $this->databaseManager->database();
 }

 public function decrease(Id $productId, Id $skuId, Quantity $quantity): void
 {
 $affected = $this->database->execute(
 'UPDATE `shop_product_sku` SET `quantity` = `quantity` - ? WHERE `id` = ? AND `product_id` = ? AND `quantity` > 0',
 [
 $quantity->toInt(),
 $skuId,
 $productId,
 ]
 );

 if ($affected === 0) {
 throw DomainException::from('库存不足,无法减少库存量', [
 'id' => $productId,
 ]);
 }
 }

 // ...
}

/**
 * 下单.
 */
class PlaceOrderCommand
{
 public function __construct(
 private SkuRepositoryInterface $skuRepository,
 private UserRepositoryInterface $userRepository,
 private OrderRepositoryInterface $orderRepository,
 private OrderFactory $orderFactory,
 private QuantityManagerInterface $quantityManager,
 private TransactionInterface $transaction,
 ) {
 }

 public function execute(
 Id $userId,
 int $productId,
 int $skuId,
 int $quantity,
 array $fulfillmentData,
 ): array {
 // ...

 $order = $this->orderFactory->create($user, $product, $sku, $quantity);

 $this->transaction->execute(function () use ($order, $user) {
 $this->orderRepository->save($order);

 // 由于QuantityManager将数据库连接作为属性, 使用的不是与orderRepository同一个连接, 导致事务失效
 $this->quantityManager->decrease($order->productId(), $order->skuId(), $order->quantity());
 });

 // ...
 }
}

正确例子:

use Lzpeng\HyperfCycle\DatabaseManager;

/**
 * 产品数量管理器.
 */
class QuantityManager implements QuantityManagerInterface
{
 public function __construct(private DatabaseManager $databaseManager)
 {
 }

 public function decrease(Id $productId, Id $skuId, Quantity $quantity): void
 {
 // 使用时才获取数据库连接,确保连接能够正确回收;
 // 同一协程内的连接实例是同一个,事务能够正常工作
 $affected = $this->databaseManager->database()->execute(
 'UPDATE `shop_product_sku` SET `quantity` = `quantity` - ? WHERE `id` = ? AND `product_id` = ? AND `quantity` > 0',
 [
 $quantity->toInt(),
 $skuId,
 $productId,
 ]
 );

 if ($affected === 0) {
 throw DomainException::from('库存不足,无法减少库存量', [
 'id' => $productId,
 ]);
 }
 }

 // ...
}