hyperf中事务操作必须绑定单一数据库连接,不可跨库或混用连接;需在config/autoload/databases.php中为各库(如log_db、report_db)独立配置完整参数及语义化名称,并通过db::connection('name')->transaction()显式指定且全程使用同一连接。

Hyperf 中事务操作切换多数据库连接,核心在于连接名显式指定 + 事务边界严格绑定到同一连接。不能跨连接开启事务,也不能在事务中混用不同连接。
明确配置多个数据库连接
在 config/autoload/databases.php 的 connections 数组中定义至少两个连接,每个连接需完整独立:
- 必须指定
driver、host、database、username、password - 每个连接应有语义化名称(如
log_db、report_db),避免用db1、db2 - 若版本或协议不同(如 MySQL 5.7 vs 8.0),必须分开配置连接池,不可复用
-
pool参数建议按实际 DB 实例承载力设置,例如max_connections不超过目标库max_connections的 70%
示例:
'connections' => [
'default' => [ /* 主库 */ ],
'log_db' => [
'driver' => 'mysql',
'host' => '192.168.1.100',
'database' => 'log_center',
'username' => 'log_user',
'password' => 'xxx',
'pool' => ['min_connections' => 2, 'max_connections' => 10],
],
'report_db' => [
'driver' => 'pgsql',
'host' => 'pg-report.internal',
'database' => 'reports',
'username' => 'rep_user',
'password' => 'yyy',
'pool' => ['min_connections' => 1, 'max_connections' => 5],
],
],
在事务中固定使用单一连接
事务必须全程运行在同一个连接实例上。调用 Db::connection('xxx') 后,所有 beginTransaction()、commit()、rollback() 都要基于该连接对象,不能中途切换。
正确写法:
use Hyperf\DbConnection\Db;
// ✅ 正确:整个事务绑定 log_db 连接
Db::connection('log_db')->transaction(function () {
Db::connection('log_db')->table('logs')->insert(['level' => 'error', 'msg' => 'timeout']);
Db::connection('log_db')->table('alerts')->insert(['type' => 'critical']);
});
错误写法(会导致事务失效或报错):
// ❌ 错误:跨连接开启事务
Db::connection('log_db')->beginTransaction();
Db::table('users')->insert([...]); // 默认走 default 连接 → 事务不生效
Db::connection('log_db')->commit();
// ❌ 错误:事务内混用连接
Db::connection('log_db')->transaction(function () {
Db::table('logs')->insert([...]); // 未指定连接 → 走 default → 不在事务内
});
Eloquent 模型中指定连接并事务兼容
若使用模型操作,需在模型类中声明 $connection 属性,且事务仍需显式指定连接:
<?php namespace App\Model;
use Hyperf\DbConnection\Model;
class LogRecord extends Model
{
protected $connection = 'log_db'; // 绑定到 log_db
protected $table = 'logs';
}事务中使用该模型时,仍推荐显式调用连接以确保一致性:
Db::connection('log_db')->transaction(function () {
LogRecord::create(['level' => 'warning']);
// 或直接使用 Query Builder
Db::connection('log_db')->table('alerts')->insert(['source' => 'api']);
});注意跨库事务的局限性
Hyperf 原生不支持分布式事务(XA)。多个数据库之间的事务无法原子性保证:
-
log_db和report_db是两个物理独立的数据库 - 无法在一个事务中同时提交/回滚二者
- 如需强一致性,应通过业务层补偿(如本地消息表 + 定时对账)或引入 Seata 等外部事务协调器
若只是单库内多表操作,无需额外处理;但涉及多库写入,应设计为「先主库后辅库」+ 「失败可逆」逻辑,而非依赖数据库级事务。
不复杂但容易忽略











