Webman不支持跨连接事务,Db::transaction()仅作用于默认连接;多库操作需手动管理各PDO实例的beginTransaction/commit/rollback,或采用补偿事务+最终一致性方案。

Webman 本身不提供跨连接事务支持,多表操作若涉及多个数据库连接(比如主库 + 日志库),Db::transaction() 无法保证原子性;只有单个 connection 内的多表操作才能用原生事务兜底。
Webman 中 Db::transaction() 只作用于默认连接
调用 Db::transaction() 时,它默认使用配置中 'default' 指定的连接(通常是 mysql),不会自动识别或切换到其他连接名。即使你在闭包里手动调用了 Db::connection('mysql2')->table(...)->insert(...),这部分操作仍游离在事务之外。
- 事务开启、提交、回滚只影响默认连接的语句执行流
-
Db::connection('mysql2')返回的是独立 PDO 实例,其 autocommit 状态、事务上下文与默认连接完全隔离 - 没有隐式传播机制,也不会报错提醒你“这个连接不在事务里”
多库场景下必须手动管理连接+事务边界
当你需要同时写主业务库和日志库,并期望“主成功则日志必须记,任一失败全撤”,就得放弃 Db::transaction() 语法糖,改用底层 PDO 控制。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 先获取两个连接的 PDO 实例:
$pdo1 = Db::connection('mysql')->getPdo();、$pdo2 = Db::connection('mysql2')->getPdo(); - 分别调用
$pdo1->beginTransaction()和$pdo2->beginTransaction() - 执行各自 SQL,全部成功后依次
$pdo1->commit()、$pdo2->commit() - 任一环节出错,按反向顺序
$pdo2->rollback()、$pdo1->rollback() - 注意:MySQL 不支持跨实例的两阶段提交(2PC),所以这种“伪分布式事务”仍有极小概率出现不一致(如 commit 第一个成功、第二个网络超时)
更稳妥的做法是用补偿事务 + 最终一致性
真正生产级的多库写入,应该放弃强一致性幻想,转而设计可重试、可核对、可修复的流程。比如写日志失败,不是卡住整个请求,而是落本地消息队列,由后台任务重试补发。
- 主库操作成功后,把日志内容写入 Redis 队列或本地文件,标记为 “pending_log”
- 启动一个异步 Worker 消费该队列,尝试插入
mysql2;成功则删队列项,失败则延时重试(带最大次数限制) - 另起定时任务扫描“超时 pending_log”,人工介入或触发告警
- 避免在 HTTP 请求链路里做跨库事务,否则响应时间不可控、连接占用时间拉长、容易被 nginx 超时切断
最常被忽略的一点:Webman 的常驻进程模型会让未关闭的 PDO 连接长期持有,如果手动调用 beginTransaction() 后忘了 commit() 或 rollback(),这个连接会一直处在事务状态,后续复用时可能意外继承 open transaction,导致锁表或查询结果异常。务必确保每个 begin 都有配对的结束动作,哪怕用 finally 块兜底。

















