Laravel多数据库切换必须显式声明作用层:模型层用$connection属性或on()方法,查询构造器层用DB::connection(),全局默认连接由config('database.default')决定;各层互不影响,且所有连接名、环境变量、配置键须严格对应,大小写敏感。

直接切,但必须明确切的是哪一层:模型层、查询构造器层,还是全局默认连接。Laravel 不会自动“感知”你要切到哪个库,所有切换都得显式声明,否则一律走 config('database.default') 配置的连接。
配置多个连接时,database.php 的命名和环境变量要严格对应
比如你加了一个叫 mysql_center 的连接,那 .env 里就得有配套的 DB_DATABASE_CENTER、DB_USERNAME_CENTER(或统一用 DB_HOST_TWO 这类后缀),不能只写一个 DB_DATABASE 就指望它自动分发。
-
database.php中连接键名(如'mysql_center')必须和你在代码里传给DB::connection('...')或Model::on('...')的字符串完全一致,大小写敏感 - 每个连接块里的
'database'字段必须调用env()读取独立变量,不能复用DB_DATABASE - 别漏掉
'driver'—— 即使都是 MySQL,也得写'driver' => 'mysql',否则 Laravel 会 fallback 到默认驱动并静默失败
DB::connection('xxx') 和 Model::on('xxx') 的行为差异
前者是查询构造器层面的临时切换,后者是 Eloquent 模型实例级的连接绑定,二者不共享状态。一个常见错误是:在控制器里写了 DB::connection('mysql_center')->table('users')->get(),以为后续的 User::find(1) 也会走这个库 —— 实际不会,User 仍按自己的 $connection 属性或默认连接走。
-
DB::connection('xxx')只影响当次链式调用,下一行不带connection()就回归默认连接 -
Model::on('xxx')返回的是一个新实例(非静态代理),所以User::on('mysql_center')->where(...)->get()是 OK 的;但$user = new User; $user->on('mysql_center')不生效,得写成$user->setConnection('mysql_center') - 关联查询(
$post->user)永远使用被关联模型自身定义的$connection,不会继承主模型的on()设置
Auth 系统相关模型和表必须显式绑定连接
Laravel 自带的认证逻辑(登录、密码重置、注册)全部依赖 config('auth.providers.users.model') 指向的模型,而该模型若没设 $connection,就会连错库。哪怕你在 User 模型里写了 protected $connection = 'mysql_center',也得确认 config/auth.php 里 'table' 键没被硬编码成 'users' —— 因为 password_resets 表如果不在同一库,重置流程会查不到记录。
-
User模型必须设protected $connection = 'mysql_center' -
config/auth.php中的'table'不用改(它只控制用户表名,不控制库),但password_resets表所在的迁移和模型(如有自定义)也要确保连对库 - 如果用了
HasApiTokens,personal_access_tokens表也得在同一个库,否则 token 验证失败
动态切换时最易踩的坑:事务、队列和连接复用
Laravel 11+ 默认启用连接复用和预处理语句缓存,跨连接混用 DB::transaction() 或在队列任务里调用 DB::setDefaultConnection() 会导致连接污染或缓存错绑,现象是查到旧数据、报 Table not found 或事务不回滚。
- 避免在单个事务里跨多个连接操作,Laravel 不支持分布式事务
- 不要在中间件或请求生命周期早期调用
DB::setDefaultConnection('xxx'),它会影响后续所有未显式指定连接的查询,包括日志、事件监听器甚至 Horizon 的队列监控表 - 队列任务中切换连接,必须在任务 handle() 开头就用
DB::connection('xxx')->...或Model::on('xxx'),不能依赖上层请求的连接上下文 - 如果用了数据库连接池(如 PDO 持久连接),确保每个连接名对应独立的 PDO 实例,而不是复用同一个 socket
真正麻烦的不是“怎么切”,而是“切完之后谁还在用旧连接”——模型、关联、填充、迁移、队列、事件监听器、甚至 Telescope 的查询记录,都可能各自持有连接引用。每次切换前,先想清楚作用域边界在哪里。


















