ThinkPHP数据库配置核心是分层加载与动态解析机制:优先读取.env文件,再由config/database.php通过env()映射多连接,Config类深度合并配置,Connection延迟初始化PDO连接,多库通过连接名路由隔离。

ThinkPHP 的数据库配置不是靠“猜”或“复制粘贴”就能真正掌握的,它背后是一套分层加载、动态解析、作用域隔离的机制。理解它的源码逻辑,能帮你快速定位连接失败、多库切换异常、环境变量不生效等问题。
配置文件位置与加载顺序
ThinkPHP 6+ 主要依赖 /config/database.php 作为主配置入口,但该文件本身不直接定义连接参数,而是通过 env() 函数从 .env 文件读取,并支持多连接定义(如 mysql、mysql2)。框架在启动时按以下顺序加载:
-
.env 文件:最优先,用于区分开发/生产环境,例如
DATABASE.HOSTNAME=127.0.0.1 -
/config/database.php:定义
connections数组,每个连接项调用env('database.xxx')或env('database2.xxx')映射 -
运行时覆盖:可通过
Db::connect([...])或模型中$connection属性临时指定,绕过配置文件
Config 类如何解析 database.php
核心类 think\Config 负责加载和归并配置。当执行 Config::load('database') 时,实际触发的是 parse() 方法:
- 先判断是否为 PHP 文件——是,则
include并返回数组结果 - 对返回数组做深度合并(
array_merge_recursive风格),但不会覆盖已存在键,除非显式重写 - 若启用作用域(
range),则把配置挂到self::$config[$range]下,避免全局污染 -
database.php返回的connections最终被 Db 类用来初始化连接实例池
连接对象 Connection 的初始化关键点
真正建立 PDO 连接发生在 Connection->__construct() 和 connect() 中:
立即学习“PHP免费学习笔记(深入)”;
-
__construct()仅保存配置,不做连接;延迟到首次查询才触发connect() -
connect()内部调用parseDsn()拼接 DSN 字符串,例如:mysql:host=127.0.0.1;port=3306;dbname=v1kcom;charset=utf8 - 字符集处理很关键:
charset配置会同时影响 DSN 中的charset参数和 PDO 的PDO::MYSQL_ATTR_INIT_COMMAND(如SET NAMES utf8mb4) - 连接失败时抛出
PDOException,但框架会捕获并包装为think\db\exception\DataNotFoundException
多库场景下的配置隔离实践
ThinkPHP 支持在同一请求中操作多个数据库,靠的是连接名路由而非全局切换:
- 在
database.php中定义多个 connection 键,如'mysql'和'mysql2' - 查询时显式指定:
Db::connect('mysql2')->table('log')->select() - 模型绑定特定库:
protected $connection = 'mysql2';,该设置优先级高于全局配置 - 注意事务限制:跨库事务无法原生保证一致性,需应用层协调或改用分布式事务方案



















