工厂模式本身不解决多数据库切换问题,它只负责创建连接;真正动态切换需运行时按配置或键名(如'payment_db')决定驱动与参数,并每次新建连接或交由连接池管理,避免单例缓存、硬编码DSN及会话级设置遗漏。

直接说结论:工厂模式本身不解决多数据库切换问题,它只负责“创建连接”,真正要动态切换,得靠运行时决定用哪个配置、哪个驱动,再交给工厂去实例化。
为什么单纯写个 DatabaseFactory 会踩坑?
常见错误是把工厂写成静态配置分发器,比如:DatabaseFactory::create('mysql') 固定返回 MySQL 实例,但实际业务中你可能需要同一请求里先后操作 mysql 和 pgsql,甚至同是 MySQL 但连的是不同库(orders_db vs users_db)。这时候如果工厂内部缓存了单例、或硬编码了 DSN,就完全没法切换。
- 工厂类不能自己保存连接实例,否则下次调用会被复用 —— 应该每次
create()都新建连接(或由连接池管理) - 不能把数据库类型写死在方法名里(如
createMysql()),而应接受配置数组或配置名作为参数 - 没处理驱动缺失报错,比如代码里写了
pdo_pgsql但扩展没启用,PDO::__construct()抛出的PDOException容易被忽略
怎么让 DatabaseFactory 真正支持运行时切换?
核心是把“选哪个库”的决策权交给上层业务,工厂只做两件事:校验配置、实例化对应 PDO 或封装类。推荐结构:
- 配置中心统一管理所有库定义,例如
$configs['payment_db'] = ['driver' => 'mysql', 'host' => '...', 'dbname' => 'pay']; -
DatabaseFactory::create(string $configKey)根据键查配置,再按driver分支加载对应构造逻辑 - 每个 driver 分支里显式设置
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,避免静默失败 - 不自动
try/catch连接异常 —— 让调用方决定重试还是降级
示例片段:
立即学习“PHP免费学习笔记(深入)”;
// 调用方决定用哪个库
$paymentDb = DatabaseFactory::create('payment_db');
$userDb = DatabaseFactory::create('user_db');
// 同一事务跨库?不行,PDO 不支持,得拆成多个事务 + 补偿逻辑
切换时最容易被忽略的三个点
不是“怎么写工厂”,而是“怎么用才不出事”:
-
PDO连接默认不支持跨库事务(哪怕同是 MySQL),START TRANSACTION只对当前连接生效;想保证一致性,得用 TCC 或消息队列 - 字符集和时区容易继承错 —— 比如主库设了
utf8mb4,从库配置漏了charset参数,插入 emoji 直接报错SQLSTATE[HY000]: General error: 1366 Incorrect string value - 长连接复用下,
SET NAMES或SET TIME_ZONE这类会话级命令必须每次查询前重置,不能依赖连接初始化时的一次设置
多数据库不是换几个配置就能跑通的事,工厂只是起点;关键在配置可追溯、连接生命周期清晰、错误能立刻暴露 —— 否则切着切着就变成“不知道连上了哪个库”。



















