在 config/database.php 中添加第二个 mysql 连接需定义完整配置项(如 mysql_secondary),确保 driver、host、port、database 等均通过 env() 加载且与 .env 中变量名严格对应,并执行 php artisan config:clear 清除缓存。

怎么在 config/database.php 里加第二个 MySQL 连接
Laravel 允许你在同一个应用里配多个数据库连接,关键不是“能不能”,而是配置时别漏掉驱动和前缀的对应关系。比如你新加一个叫 mysql_secondary 的连接,必须确保它和主连接一样,driver 是 mysql,且 host、database、username 等字段都填全——少一个就会报 SQLSTATE[HY000] [1045] Access denied 或直接连不上。
常见错误是复制主连接后只改了 database 名,忘了改 host 或用了错的 port;还有人把 prefix 设成空字符串但没加引号,PHP 会当成未定义常量报错。
'mysql_secondary' => [ 'driver' => 'mysql', 'host' => env('DB_SECONDARY_HOST', '127.0.0.1'), 'port' => env('DB_SECONDARY_PORT', '3306'), 'database' => env('DB_SECONDARY_DATABASE', 'forge'), 'username' => env('DB_SECONDARY_USERNAME', 'forge'), 'password' => env('DB_SECONDARY_PASSWORD', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', ]- 所有值必须从
.env拉,别硬编码;环境变量名要和配置键对得上,比如DB_SECONDARY_HOST对应env('DB_SECONDARY_HOST') - 改完记得清配置缓存:
php artisan config:clear,否则新连接根本不会被加载
模型里怎么指定用哪个数据库连接
模型默认走 config/database.php 里 'default' 指定的那个连接。想让它走别的,就设 $connection 属性。这个值必须和配置里的连接名完全一致,包括大小写和下划线。
容易踩的坑是:以为只要在查询时临时切就行,结果发现 Model::on('mysql_secondary')->get() 虽然能查,但关联查询(with())还是走默认连接;或者用了 on() 却忘了后续的 save()、delete() 仍走默认连接,造成数据错位。
- 在模型类里写:
protected $connection = 'mysql_secondary'; - 如果只是临时切换一次查询,用
User::on('mysql_secondary')->where(...)->get(),但注意它不改变模型本身的连接设置 - 关联模型不会自动继承父模型的
$connection,每个关联模型得自己设,否则一查user->posts就回到主库
事务跨库会失败,别指望 DB::transaction() 包住两个库
Laravel 的 DB::transaction() 底层调的是单个 PDO 实例的 beginTransaction(),它只能管一个数据库连接。如果你在事务里混用 DB::connection('mysql_primary') 和 DB::connection('mysql_secondary'),那两个连接各自开启、提交、回滚,完全不联动——看着像在事务里,其实毫无原子性可言。
真实场景里,这种需求往往出现在迁移旧数据或双写同步,这时候得手动控制:先在一个库操作并记录状态,再调另一个库,失败了靠补偿逻辑兜底,而不是幻想一个 transaction() 能横跨两套 MySQL 实例。
- 不要写:
DB::transaction(function () { DB::connection('mysql_primary')→table(...)->insert(...); DB::connection('mysql_secondary')→table(...)->insert(...); }); - 如果真要强一致性,得用分布式事务方案(比如 XA),但 Laravel 原生不支持,MySQL 也得开
xa相关配置,实际项目中极少用 - 多数情况应该拆成两步:先写主库,成功后再异步发消息去写副库,失败走重试+告警
连接名写错、环境没生效、缓存没清——这三个地方最容易卡住调试
配好多库后跑不通,90% 的问题不在逻辑,而在环境链路断了。最典型的是:本地 .env 改了,但服务器上没同步;或者 config:cache 之后改了配置却忘了 config:clear;再或者代码里写了 on('mysql_sec'),而配置里是 mysql_secondary,拼写差一个字母就静默 fallback 到默认连接,还查不出错。
建议调试时直接在 tinker 里验证连接是否真通:DB::connection('mysql_secondary')->select('select 1 as ok');,别等业务逻辑跑起来才怀疑。
- 检查连接名是否完全一致:
config('database.connections.mysql_secondary')在 tinker 里输出看看 - 确认当前环境加载的是哪个配置文件,
app()->environment()和env('APP_ENV')是否一致 - 部署后务必执行
php artisan config:clear,缓存不清理,改十遍配置也没用
多库本身不难,难的是每个环节都得对齐:配置名、环境变量、模型声明、运行时调用、缓存状态——漏一个,就变成“明明配了却没走”的玄学问题。











