引言:
PHP 调用 SQLite 数据库主要通过 SQLite3 扩展和 PDO_SQLITE 驱动实现。本文系统讲解环境配置、两种连接方式、数据增删改查、预处理语句防护 SQL 注入、事务处理、内存数据库及错误处理机制,帮助 PHP 开发者快速掌握轻量级嵌入式数据库的使用方法。
PHP 的 SQLite 数据库调用完全指南
SQLite 是一种轻量级的嵌入式关系型数据库引擎,与 PHP 配合使用非常便捷。它不像 MySQL 或 PostgreSQL 那样需要独立的服务器进程,而是将整个数据库存储为一个普通的文件,通过直接读写该文件来完成所有数据库操作。PHP 原生内置了对 SQLite 的支持,无需额外安装复杂的数据库服务,这使得它非常适合小型 Web 应用、移动应用后台、嵌入式系统以及数据分析和缓存等场景。
本文将系统讲解 PHP 中操作 SQLite 数据库的完整流程,涵盖环境配置、两种主流扩展的使用、数据增删改查、预处理语句防护、事务处理以及错误处理机制。
一、环境准备:安装与启用 SQLite 扩展
在开始编码之前,需要确保 PHP 环境已经安装并启用了 SQLite 相关的扩展。
1. 确认扩展状态
PHP 的 SQLite3 扩展在大多数发行版中默认是启用的。可以通过 php -m 命令检查是否已加载:
正常输出应包含 sqlite3 和 pdo_sqlite,表示扩展已可用。
2. 各平台安装方式
Ubuntu/Debian 系统:
1
| sudo apt install php8.1-sqlite3
|
安装后扩展会自动启用。
Windows 系统:
在 php.ini 配置文件中取消 extension=php_sqlite3.dll 前的注释符号(分号),保存后重启 Web 服务器。同时需要确保 libsqlite3.dll 文件在系统 PATH 路径中。
macOS 系统(使用 Homebrew):
1 2 3
| brew install php@8.2
pecl install sqlite3
|
3. 验证扩展安装
创建一个包含 phpinfo(); 的 PHP 文件,在浏览器中访问,搜索 sqlite3 或 pdo_sqlite 确认扩展已加载。
二、两种连接方式
PHP 连接 SQLite 主要有两种方式:SQLite3 扩展(面向对象,专为 SQLite 设计)和 PDO_SQLITE 驱动(数据库抽象层)。
方式一:SQLite3 扩展(原生,专为 SQLite 设计)
SQLite3 扩展是 PHP 官方为 SQLite 提供的原生接口,以面向对象的方式提供完整的 SQLite 操作能力。
特点:
- 无需额外依赖,PHP 默认启用
- 专为 SQLite 优化,API 简洁直观
- 适合 SQLite 专属项目
示例:创建连接与获取版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php
$db = new SQLite3('test.db');
$version = SQLite3::version(); echo "版本字符串: " . $version['versionString'] . "\n"; echo "版本号: " . $version['versionNumber'] . "\n";
$version = $db->querySingle('SELECT SQLITE_VERSION()'); echo "SQL 查询版本: " . $version . "\n";
$db->close(); ?>
|
SQLite 的连接字符串就是一个文件路径。如果文件不存在,SQLite 会自动创建它。:memory: 是特殊值,表示在内存中创建数据库,数据不会持久化保存。
方式二:PDO_SQLITE 驱动(数据库抽象层)
PDO(PHP Data Objects)提供了统一的数据库访问接口,使用 PDO_SQLITE 驱动可以让代码在多种数据库之间平滑切换。
示例:使用 PDO 连接 SQLite:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php try { $pdo = new PDO('sqlite:/path/to/database.db'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); echo "成功连接到 SQLite 数据库!"; } catch (PDOException $e) { die("连接失败:" . $e->getMessage()); }
$pdo = null; ?>
|
两种方式对比
| 特性 |
SQLite3 扩展 |
PDO_SQLITE |
| 数据库支持 |
仅 SQLite |
支持 12+ 种数据库 |
| 接口风格 |
面向对象 |
面向对象 |
| 预处理语句 |
支持(prepare/bindValue) |
支持(prepare/execute) |
| 命名参数 |
支持(:id 格式) |
支持(:name 格式) |
| 异常处理 |
需手动检查 |
原生支持 try-catch |
| 适用场景 |
SQLite 专属项目 |
跨数据库项目或需要统一接口 |
三、核心数据库操作
以下操作以 SQLite3 扩展为主,同时给出 PDO 的对应写法。
1. 创建表与插入数据(exec)
exec 方法用于执行不返回结果集的 SQL 语句(如 CREATE、INSERT、UPDATE、DELETE)。
SQLite3 扩展示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?php $db = new SQLite3('test.db');
$sql = "CREATE TABLE IF NOT EXISTS cars ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INT )"; $db->exec($sql);
$cars = [ ['Audi', 52642], ['Mercedes', 57127], ['Skoda', 9000], ['Volvo', 29000], ['Bentley', 350000], ['Citroen', 21000], ['Hummer', 41400], ['Volkswagen', 21600] ];
foreach ($cars as $car) { $db->exec("INSERT INTO cars (name, price) VALUES ('{$car[0]}', {$car[1]})"); }
echo "数据插入成功!"; $db->close(); ?>
|
PDO 对应写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php $pdo = new PDO('sqlite:test.db'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec("CREATE TABLE IF NOT EXISTS cars ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INT )");
$pdo->exec("INSERT INTO cars (name, price) VALUES ('Audi', 52642)"); $pdo->exec("INSERT INTO cars (name, price) VALUES ('Mercedes', 57127)");
echo "数据插入成功!"; $pdo = null; ?>
|
2. 查询数据(query 与 fetchArray)
query 方法执行 SQL 查询并返回结果对象,通过 fetchArray 逐行获取数据。
SQLite3 扩展示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php $db = new SQLite3('test.db');
$result = $db->query('SELECT id, name, price FROM cars ORDER BY price DESC');
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { echo "ID: {$row['id']} - Name: {$row['name']} - Price: {$row['price']}\n"; }
$result = $db->query('SELECT * FROM cars'); while ($row = $result->fetchArray(SQLITE3_NUM)) { echo "{$row[0]} {$row[1]} {$row[2]}\n"; }
$db->close(); ?>
|
PDO 对应写法:
1 2 3 4 5 6 7 8 9 10 11
| <?php $pdo = new PDO('sqlite:test.db'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query('SELECT id, name, price FROM cars ORDER BY price DESC'); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { echo "ID: {$row['id']} - Name: {$row['name']} - Price: {$row['price']}\n"; }
$pdo = null; ?>
|
3. 单值查询(querySingle)
querySingle 方法用于执行查询并直接返回第一行第一列的值。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php $db = new SQLite3('test.db');
$count = $db->querySingle('SELECT COUNT(*) FROM cars'); echo "共有 {$count} 条记录\n";
$maxPrice = $db->querySingle('SELECT MAX(price) FROM cars'); echo "最高价格: {$maxPrice}\n";
$db->close(); ?>
|
4. 更新与删除数据
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php $db = new SQLite3('test.db');
$db->exec("UPDATE cars SET price = 30000 WHERE name = 'Skoda'"); echo "更新成功\n";
$db->exec("DELETE FROM cars WHERE name = 'Hummer'"); echo "删除成功\n";
$db->close(); ?>
|
四、获取最后插入的 ID
当使用 INTEGER PRIMARY KEY 列时,SQLite 会自动为插入的行生成递增的 ID。可以通过 lastInsertRowID 方法获取最后插入行的 ID。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php $db = new SQLite3('test.db');
$db->exec("CREATE TABLE IF NOT EXISTS friends ( id INTEGER PRIMARY KEY, name TEXT )");
$db->exec("INSERT INTO friends (name) VALUES ('Tom')"); $db->exec("INSERT INTO friends (name) VALUES ('Rebecca')"); $db->exec("INSERT INTO friends (name) VALUES ('Jim')");
$lastId = $db->lastInsertRowID(); echo "最后插入的 ID 是: {$lastId}\n";
$db->close(); ?>
|
五、预处理语句与 SQL 注入防护
预处理语句是防御 SQL 注入攻击的标准做法,也是构建安全应用的关键环节。
SQLite3 扩展中的预处理语句
SQLite3 扩展支持两种占位符语法:问号占位符和命名占位符(以 : 开头)。
使用命名占位符:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php $db = new SQLite3('test.db');
$stmt = $db->prepare('SELECT * FROM cars WHERE id = :id');
$stmt->bindValue(':id', 3, SQLITE3_INTEGER);
$result = $stmt->execute();
$row = $result->fetchArray(SQLITE3_ASSOC); echo "ID: {$row['id']} - Name: {$row['name']} - Price: {$row['price']}\n";
$db->close(); ?>
|
使用问号占位符:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php $db = new SQLite3('test.db');
$stmt = $db->prepare('SELECT * FROM cars WHERE id = ?'); $stmt->bindValue(1, 1, SQLITE3_INTEGER);
$result = $stmt->execute(); $row = $result->fetchArray(SQLITE3_NUM); echo "{$row[0]} {$row[1]} {$row[2]}\n";
$db->close(); ?>
|
插入数据时使用预处理语句:
1 2 3 4 5 6 7 8 9 10 11 12
| <?php $db = new SQLite3('test.db');
$stmt = $db->prepare('INSERT INTO cars (name, price) VALUES (:name, :price)'); $stmt->bindValue(':name', 'Tesla', SQLITE3_TEXT); $stmt->bindValue(':price', 75000, SQLITE3_INTEGER); $stmt->execute();
echo "插入成功,ID: " . $db->lastInsertRowID() . "\n";
$db->close(); ?>
|
始终检查 prepare 的返回值:如果 SQL 语句有语法错误,prepare 会返回 false。如果不检查就调用 execute(),会导致致命错误。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php $db = new SQLite3('test.db');
$stmt = $db->prepare('SELECT * FROM cars WHERE id = :id'); if ($stmt === false) { die("预处理失败: " . $db->lastErrorMsg()); }
$stmt->bindValue(':id', 1, SQLITE3_INTEGER); $result = $stmt->execute();
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { print_r($row); }
$db->close(); ?>
|
PDO 预处理语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php $pdo = new PDO('sqlite:test.db'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('SELECT * FROM cars WHERE id = :id'); $stmt->execute([':id' => 3]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { print_r($row); }
$stmt = $pdo->prepare('SELECT * FROM cars WHERE id = ?'); $stmt->execute([1]);
$pdo = null; ?>
|
六、事务处理
SQLite 支持 ACID 事务,保证数据的一致性和完整性。虽然 SQLite3 扩展没有专门的事务方法,但可以通过执行 SQL 语句来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php $db = new SQLite3('test.db');
try { $db->exec('BEGIN TRANSACTION'); $db->exec("UPDATE cars SET price = price + 1000 WHERE name = 'Audi'"); $db->exec("UPDATE cars SET price = price + 500 WHERE name = 'Skoda'"); $db->exec('COMMIT'); echo "事务提交成功\n"; } catch (Exception $e) { $db->exec('ROLLBACK'); echo "事务回滚:" . $e->getMessage() . "\n"; }
$db->close(); ?>
|
PDO 事务处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php $pdo = new PDO('sqlite:test.db'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try { $pdo->beginTransaction(); $pdo->exec("UPDATE cars SET price = price + 1000 WHERE name = 'Audi'"); $pdo->exec("UPDATE cars SET price = price + 500 WHERE name = 'Skoda'"); $pdo->commit(); echo "事务提交成功\n"; } catch (PDOException $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } echo "事务回滚:" . $e->getMessage() . "\n"; }
$pdo = null; ?>
|
七、错误处理
SQLite3 扩展错误处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php $db = new SQLite3('test.db');
$result = $db->exec("INSERT INTO non_existent_table (name) VALUES ('test')");
if ($result === false) { echo "错误代码: " . $db->lastErrorCode() . "\n"; echo "错误信息: " . $db->lastErrorMsg() . "\n"; }
$db->close(); ?>
|
PDO 错误处理(异常模式)
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php try { $pdo = new PDO('sqlite:test.db'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->exec("INSERT INTO non_existent_table (name) VALUES ('test')"); } catch (PDOException $e) { echo "错误代码: " . $e->getCode() . "\n"; echo "错误信息: " . $e->getMessage() . "\n"; }
$pdo = null; ?>
|
八、内存数据库
SQLite 支持在内存中创建数据库,数据不会持久化保存,适合临时缓存或测试场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php
$db = new SQLite3(':memory:');
$db->exec("CREATE TABLE temp (id INTEGER PRIMARY KEY, value TEXT)"); $db->exec("INSERT INTO temp (value) VALUES ('临时数据')");
$result = $db->query("SELECT * FROM temp"); while ($row = $result->fetchArray(SQLITE3_ASSOC)) { print_r($row); }
$db->close(); ?>
|
九、字符转义
在拼接 SQL 语句时,建议使用预处理语句而非手动转义。如果确实需要手动转义,可以使用 escapeString 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php $db = new SQLite3('test.db');
$userInput = "O'Reilly";
$escaped = SQLite3::escapeString($userInput);
$db->exec("INSERT INTO cars (name, price) VALUES ('$escaped', 1000)");
$db->close(); ?>
|
十、推荐的最佳实践
| 实践建议 |
说明 |
| 使用预处理语句 |
永远不要直接拼接用户输入到 SQL 中,使用预处理语句防止 SQL 注入 |
| 启用外键约束 |
执行 PRAGMA foreign_keys = ON 启用外键检查,保证数据完整性 |
| 使用 WAL 日志模式 |
执行 PRAGMA journal_mode=WAL 提升并发读写性能 |
| 生产环境关闭错误显示 |
使用 error_reporting(0) 避免暴露敏感信息 |
| 合理使用内存数据库 |
临时数据使用 :memory: 提升性能 |
| 及时关闭连接 |
脚本结束时调用 close() 或 $pdo = null 释放资源 |
总结
PHP 与 SQLite 的组合因其零配置、开箱即用的特性,成为轻量级 Web 应用、移动应用后端和嵌入式系统的理想选择。
核心要点可归纳为:
- 选择扩展:SQLite3 扩展适合 SQLite 专属项目;PDO_SQLITE 适合跨数据库或需要统一接口的项目
- 安全第一:始终使用预处理语句防止 SQL 注入
- 零配置优势:无需安装数据库服务,数据库就是一个普通文件,便于部署和迁移
- 事务处理:使用事务保证数据一致性
掌握这些基础操作后,可以进一步学习 SQLite 的高级特性,如全文搜索(FTS5)、JSON 支持、窗口函数以及自定义聚合函数等,构建更强大的 Web 应用。