Hyperf 中批量同步数据并切换多数据库连接,核心是动态管理连接、避免泄漏、保证事务一致性;需在 config/autoload/databases.php 配置多个命名连接(如 default/slave/backup),运行时通过 Db::connection('name') 按需获取,分页处理+单库事务封装,禁止跨库事务。

Hyperf 中批量同步数据并切换多数据库连接,核心在于动态管理数据库连接、避免连接泄漏、保证事务一致性。不建议在单次请求中硬编码多个 DB 实例,而应利用 Hyperf 的 DI 容器和 DbConnectionPool 机制按需切换。
配置多个数据库连接
在 config/autoload/databases.php 中定义多个连接,例如:
'default' => [
'driver' => env('DB_DRIVER', 'mysql'),
'host' => env('DB_HOST', 'localhost'),
'port' => (int) env('DB_PORT', 3306),
'database' => env('DB_DATABASE', 'db_main'),
// ...
],
'slave' => [
'driver' => env('DB_SLAVE_DRIVER', 'mysql'),
'host' => env('DB_SLAVE_HOST', '192.168.1.100'),
'port' => (int) env('DB_SLAVE_PORT', 3306),
'database' => env('DB_SLAVE_DATABASE', 'db_slave'),
// ...
],
'backup' => [
'driver' => env('DB_BACKUP_DRIVER', 'mysql'),
'host' => env('DB_BACKUP_HOST', '192.168.1.200'),
'port' => (int) env('DB_BACKUP_PORT', 3306),
'database' => env('DB_BACKUP_DATABASE', 'db_backup'),
// ...
],
确保每个连接有唯一 name(如 default、slave、backup),后续可通过名字获取对应连接池。
运行时按需获取指定连接
在服务或命令中,使用 Db::connection('backup') 或 $container->get(DbFactory::class)->get('backup') 获取目标连接实例。推荐封装一个工具方法:
- 用
Db::connection('xxx')获取连接后,直接调用table()、select()等链式操作 - 避免长期持有连接对象,尤其在协程环境下,每次操作完让连接自动归还到池中
- 若需事务,必须在同一个连接实例上调用
beginTransaction()→commit()/rollback()
批量同步时控制连接与事务边界
同步过程通常涉及「读 A 库 → 处理 → 写 B 库」,关键点如下:
- 读取端使用
Db::connection('source')->table(...)->get(),写入端用Db::connection('target')->table(...)->insert(...) - 大批次建议分页处理(如每 500 条一批),防止内存溢出和超时;可用
forPage()或手动 limit + offset - 写入前可先用
Db::connection('target')->transaction(function ($db) use ($data) { ... })包裹单批操作,提升可靠性 - 不要跨连接开启事务(MySQL 不支持分布式事务),各库事务独立管理
命令行脚本示例(用于定时同步)
新建 app/Command/SyncDataCommand.php:
public function handle()
{
$source = Db::connection('slave');
$target = Db::connection('backup');
$offset = 0;
$limit = 500;
do {
$rows = $source->table('orders')
->where('updated_at', '>=', '2024-01-01')
->orderBy('id')
->limit($limit)
->offset($offset)
->get();
if ($rows->isEmpty()) break;
$target->table('orders')->insert($rows->toArray());
$offset += $limit;
usleep(10000); // 可选:降低写入压力
} while (true);
$this->output->writeln('Sync completed.');
}
执行:php bin/hyperf.php sync:data


















