这是 Laravel 数据库架构中解耦与抽象的核心设计原则。
一、职责划分:各司其职,层次清晰
| 组件 | 职责 | 是否直接接触 PDO |
|---|---|---|
| Eloquent Model | 业务对象映射(ORM),提供User::find(1)、关联关系等 | ❌ 否 |
| Query Builder | 构建 SQL 查询(链式调用),如DB::table('users')->where(...) | ❌ 否 |
| Connection | 数据库连接的统一入口,执行 SQL、管理事务、处理异常 | ✅ 是(通过$this->pdo) |
| PDO | PHP 底层数据库驱动,执行原生预处理语句 | —— |
✅关键设计:上层组件(Eloquent / Query Builder)只依赖
Connection接口,完全不感知 PDO、MySQL、PostgreSQL 等细节。
二、交互流程:一次查询如何流转?
以User::where('email', 'john@example.com')->first()为例:
Eloquent
→ 调用newModelQuery(),内部使用getQuery()获取一个Query Builder 实例。Query Builder
→ 构建查询结构(wheres,selects等),最终调用$this->connection->select($sql, $bindings)。Connection
→ 持有protected $pdo;(即PDO实例)
→ 调用$this->pdo->prepare($sql)->execute($bindings)
→ 捕获PDOException并包装为QueryException
→ 返回结果数组Eloquent
→ 将数组结果转换为User模型实例
🔁整个过程,Eloquent 和 Query Builder 从未直接调用
new PDO(...)或$pdo->prepare()。
三、封装价值:为什么这样做?
1.解耦数据库实现
- 替换数据库(MySQL → PostgreSQL)只需改配置,上层代码零修改。
- 因为
Connection的select(),insert()方法签名统一,内部适配不同 SQL 方言(通过Grammar)。
2.统一错误处理
- 所有数据库错误在
Connection层被捕获 → 转为QueryException→ 由全局异常处理器(Handler)统一响应。 - 避免各处散落
try/catch(PDOException)。
3.增强可测试性
- 可对
Connection进行 Mock,无需真实数据库:$mockConnection=Mockery::mock(Connection::class);$mockConnection->shouldReceive('select')->andReturn([['id'=>1]]); - Eloquent / Query Builder 的单元测试因此可行。
4.支持高级功能透明化
- 读写分离:
Connection内部自动选择 read / write PDO 实例。 - 事务管理:
DB::transaction()最终调用$connection->beginTransaction()。 - 查询日志:
Connection在执行前后触发events(如QueryExecuted)。
四、代码佐证(Laravel 源码片段)
Illuminate\Database\Connection
classConnection{protected$pdo;// ← 核心:持有 PDO 实例publicfunctionselect($query,$bindings=[],$useReadPdo=true){return$this->run($query,$bindings,function($query,$bindings)use($useReadPdo){$pdo=$this->getPdoForSelect($useReadPdo);$statement=$pdo->prepare($query);// ← 唯一接触 PDO 的地方$this->bindValues($statement,$bindings);$statement->execute();return$statement->fetchAll(/* ... */);});}}Illuminate\Database\Query\Builder
classBuilder{publicfunctionget($columns=['*']){return$this->connection->select(// ← 只调用 Connection,不碰 PDO$this->toSql(),$this->getBindings(),!$this->useWritePdo);}}总结
“Laravel 的 Connection 类通过 pdo 属性持有 PDO 实例,上层(Query Builder、Eloquent)只与 Connection 交互”
这句话精准概括了 Laravel 数据库层的抽象边界与依赖方向。
- ✅Connection 是“门面”:对上提供统一数据库操作接口,对下封装 PDO 细节。
- ✅上层无感知:Eloquent 与 Query Builder 专注业务逻辑与查询构建,不关心“如何连数据库”。
- ✅符合 SOLID 原则:尤其是依赖倒置原则(DIP)——高层模块不依赖低层模块,二者都依赖抽象(
ConnectionInterface)。
这种设计使得 Laravel 数据库系统既强大(支持事务、日志、读写分离),又灵活(可替换数据库、可测试、可扩展),是框架工程化思维的典范。