在 config/database.php 的 'connections' 数组中新增键值对(如 'mysql_log'),完整配置 driver、host、port、database、username、password,并通过 db::connection('mysql_log')->table()->get() 链式调用或模型 $connection 属性绑定使用。

怎么在 config/database.php 里加第二个数据库连接
Laravel 不限制数据库连接数量,关键是在配置文件里正确定义新连接,而不是只改 default。一个常见错误是直接复制 mysql 块但漏掉键名或没配 database 字段,导致 DB::connection('xxx') 找不到连接。
实操建议:
- 在
config/database.php的'connections'数组里新增一个键值对,比如'mysql_log',不要用下划线开头或纯数字命名 - 每个连接必须包含
driver、host、port、database、username、password,缺一不可;database是实际库名,不是连接别名 - 如果两个 MySQL 实例端口不同(比如主库 3306、日志库 3307),
port必须显式写出来,不能依赖默认值 - 环境变量要用
env('DB_LOG_DATABASE')这种方式读取,别硬编码,否则上线后切环境就炸
DB::connection('xxx') 怎么选对连接并避免查询跑错库
手动指定连接时,DB::connection('xxx') 返回的是一个独立的查询构建器实例,它不继承当前模型或全局配置的连接。最容易踩的坑是:调用了 DB::connection('log'),但后面没链式调用任何查询方法,结果还是走默认连接执行了。
实操建议:
- 必须链式调用,比如
DB::connection('mysql_log')->table('logs')->insert([...]),断开链式就会回退到默认连接 - 不要在同一个语句里混用连接,例如
DB::connection('mysql_log')->table('logs')->join('users', ...)—— 这里的users表会去mysql_log对应的库找,不是主库 - 如果要跨库关联,得用原生 SQL 或视图,Query Builder 不支持跨连接
join - 模型绑定连接更稳妥:
protected $connection = 'mysql_log';,比每次手写DB::connection()少出错
模型怎么固定用某个数据库连接而不靠运行时传参
模型级绑定连接比每次调用都指定更可靠,尤其适合日志、报表等专用表。但很多人设了 $connection 属性却没清缓存,结果改完代码查的还是旧连接。
实操建议:
- 在模型类里直接定义
protected $connection = 'mysql_log';,Laravel 会自动使用该连接,无需额外调用 - 改完
$connection后,必须运行php artisan config:clear,否则配置缓存可能让改动不生效 - 如果模型需要动态切换连接(比如按租户分库),别在构造函数里改
$this->connection,而应在查询前用on('xxx'):User::on('mysql_tenant_123')->get() -
$connection只影响该模型的默认连接,不影响它关联的其他模型 —— 关联模型仍走自己的$connection或默认值
事务跨多库会失败,那怎么保证一致性
Laravel 的 DB::transaction() 只作用于单个连接,跨库事务本质上不被 MySQL 支持(除非用 XA,但 Laravel 不内置封装)。强行在一个事务里操作两个连接,只会让其中一个提交、另一个回滚,造成数据不一致。
实操建议:
- 完全放弃「跨库事务」念头。这不是 Laravel 的锅,是底层数据库协议限制
- 用最终一致性方案替代:先在主库完成核心操作,再通过队列异步写日志库,失败时重试 + 补偿逻辑
- 如果业务强要求原子性(比如扣款+记流水),把两张表放在同一个 MySQL 实例的不同库下,用
库名.表名方式在单连接内操作,例如DB::table('main.users')->join('log.transactions', ...) - 别信网上那些“手动开启多个 PDO 事务再一起 commit”的做法,PHP 进程崩溃或异常退出时无法保证全部回滚
多连接本身不难,难的是意识不到跨库边界在哪里——连不上是配置问题,查错库是链式调用断了,事务失效是架构前提错了。这些地方一旦忽略,调试成本远高于初始化配置。











