在 Drupal 7 中操作数据库 - 第1课 - Drupal 数据库 API(DB API)
如果你曾经为 Drupal 6 编写过模块,那么迁移到新的 Drupal 7 Database API 对你来说不会太困难。新的数据库 API 基于 PHP 的 PDO 扩展,这使它能够支持多种数据库,例如 MySQL、PostgreSQL、MSSQL,甚至可能包括 Oracle。虽然语法需要一些时间去适应,但从安全性和可扩展性角度来看,它比直接书写 SQL 更强大。
以下是官方文档中的一些要点:
Drupal 7 Database API 提供了一个标准化且直观的数据库访问抽象层。该 API 在尽可能保持 SQL 语法和灵活性的同时,还提供了以下特性:
- 轻松支持多个数据库服务器;
- 允许开发者使用更复杂的数据库功能(如事务);
- 提供结构化接口,用于动态构建 SQL 查询;
- 增强安全性并遵循良好的开发实践;
- 为模块提供清晰的接口,用于拦截和修改站点查询;
- 主要文档直接包含在源码注释中,Handbook 提供模块开发者级别的入门指南,但并未涵盖 API 的所有功能;
- Database API 基于面向对象(OOP)概念实现,建议开发者具备一定的 OOP 基础。不过,大多数常见操作也可通过过程式函数实现。
Drupal Database API 的核心概念
Drupal 的数据库抽象层(db layer)基于 PHP PDO 库。PDO 为多种数据库提供统一的面向对象接口,但并不抽象不同 SQL 方言之间的差异。因此,Drupal 通过为不同数据库定义驱动(driver)来实现兼容性。
数据库驱动(Drivers)
由于不同数据库的交互方式不同,Drupal 的 DB 层为每种数据库类型提供独立驱动。驱动文件存放在 includes/database/driver
目录下,其中 driver 是该驱动的唯一标识。例如常见的有 “mysql”、 “pgsql” 或 “mycustomdriver”。
每个驱动包含多个类,这些类继承自系统核心中的父类,可以根据数据库特性重写其行为。命名规则通常为 类名_驱动名
,例如:MySQL 专用的插入类命名为 InsertQuery_mysql
。
数据库连接(Connection)
每个数据库连接都是一个 DatabaseConnection
对象,该类继承自 PHP 的 PDO 类。Drupal 为每个连接的数据库维护一个独立的连接对象。不同驱动可以通过继承来实现各自的连接类。
获取连接对象的方式如下:
<?php $conn = Database::getConnection($target, $key); ?>
如果要获取当前活动的连接,只需:
<?php $conn = Database::getConnection(); ?>
在大多数情况下,你无需直接操作连接对象,因为 Drupal 的过程式包装函数(如 db_query()
)会自动处理连接。只有在跨多个数据库执行复杂查询时,才需要手动切换连接。
切换活动连接可使用:
<?php db_set_active($key); ?>
数据库查询(Queries)
查询是要通过数据库连接执行的 SQL 语句。Drupal DB API 支持六种主要的查询类型:
- Static(静态查询)
- Dynamic(动态查询)
- Insert(插入)
- Update(更新)
- Delete(删除)
- Merge(合并)
这些查询可以通过 SQL 字符串直接执行,也可以使用 Drupal 的对象式查询构建器。对象式查询提供更高的安全性和灵活性。
构建查询对象
查询对象的声明通常始于一个 SELECT 查询。所有查询对象均继承自 DatabaseStatement
类(该类扩展自 PDOStatement
)。
Drupal 默认使用“预处理语句”(Prepared Statements),即在查询中使用占位符,值在执行时绑定。这不仅提高了执行效率,还能防止 SQL 注入攻击。
例如,在 PDO 中,一个预处理语句模板可以重复执行,每次使用不同的绑定参数。Drupal 将这一机制封装在自己的查询对象中,开发者无需直接操作 PDO 的底层方法。
换句话说,Drupal 不暴露底层的 PDO 预处理接口,而是通过自身的对象封装实现这一功能。开发者只需编写结构化查询,无需手动绑定参数。