# PHP中PDO怎么使用 ## 一、PDO简介 PDO(PHP Data Objects)是PHP中一个轻量级的、兼容性强的数据库操作抽象层。它为访问不同类型的数据库提供了统一的接口,开发者无需针对不同数据库编写特定代码。 ### 1.1 PDO核心优势 - **跨数据库兼容性**:支持MySQL、PostgreSQL、SQLite等12+种数据库 - **预处理语句**:内置防止SQL注入的机制 - **面向对象接口**:更符合现代PHP编程范式 - **错误处理**:多种错误模式可选 - **事务支持**:简化复杂数据库操作 ### 1.2 与mysql/mysqli扩展对比 | 特性 | PDO | mysql/mysqli | |---------------|----------------|--------------------| | 数据库支持 | 多数据库 | 仅MySQL | | API风格 | 纯面向对象 | 混合风格 | | 预处理 | 统一语法 | 不同实现 | | 命名参数 | 支持 | 不支持 | ## 二、PDO基本使用 ### 2.1 建立数据库连接 ```php <?php try { $dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4'; $username = 'db_user'; $password = 'db_pass'; $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]; $pdo = new PDO($dsn, $username, $password, $options); } catch (PDOException $e) { die("连接失败: " . $e->getMessage()); }
参数说明: - $dsn
:数据源名称,格式驱动名:host=主机;dbname=数据库名
- charset
:强烈建议设置为utf8mb4以支持完整Unicode - $options
常用配置: - ERRMODE_EXCEPTION
:错误时抛出异常 - FETCH_ASSOC
:默认返回关联数组 - EMULATE_PREPARES
:禁用预处理模拟
// 查询示例 $stmt = $pdo->query('SELECT * FROM users LIMIT 5'); $results = $stmt->fetchAll(); // 插入示例 $affectedRows = $pdo->exec(" INSERT INTO users(username, email) VALUES('john', 'john@example.com') ");
// 位置参数 $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ? AND status = ?"); $stmt->execute([$id, $status]); // 命名参数 $stmt = $pdo->prepare(" INSERT INTO products(name, price) VALUES(:name, :price) "); $stmt->execute([ ':name' => $productName, ':price' => $price ]);
$stmt = $pdo->prepare("SELECT * FROM posts WHERE category = ?"); $stmt->bindValue(1, $category, PDO::PARAM_STR); $stmt->execute(); // 绑定输出参数(存储过程) $stmt = $pdo->prepare("CALL get_user_stats(?, ?)"); $stmt->bindParam(1, $userId, PDO::PARAM_INT); $stmt->bindParam(2, $output, PDO::PARAM_STR, 100); $stmt->execute();
// 获取单行 $row = $stmt->fetch(); // 获取所有结果 $allRows = $stmt->fetchAll(); // 遍历结果集 while ($row = $stmt->fetch()) { echo $row['username']; } // 获取单列 $emails = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
// 获取stdClass对象 $stmt->setFetchMode(PDO::FETCH_OBJ); // 映射到自定义类 class User {} $stmt->setFetchMode(PDO::FETCH_CLASS, 'User');
try { $pdo->beginTransaction(); $stmt1 = $pdo->prepare("UPDATE accounts SET balance = balance - ? WHERE id = ?"); $stmt2 = $pdo->prepare("UPDATE accounts SET balance = balance + ? WHERE id = ?"); $stmt1->execute([$amount, $fromAccount]); $stmt2->execute([$amount, $toAccount]); $pdo->commit(); } catch (Exception $e) { $pdo->rollBack(); echo "事务失败: " . $e->getMessage(); }
$data = [ ['name' => 'Product A', 'price' => 9.99], ['name' => 'Product B', 'price' => 19.99] ]; $stmt = $pdo->prepare("INSERT INTO products(name, price) VALUES(?, ?)"); foreach ($data as $row) { $stmt->execute([$row['name'], $row['price']]); }
$pdo->lastInsertId();
$stmt = $pdo->prepare("CALL sp_get_user_data(?)"); $stmt->execute([$userId]);
// 设置错误模式(推荐在连接时设置) $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); try { // 数据库操作 } catch (PDOException $e) { error_log("数据库错误: " . $e->getMessage()); // 返回用户友好提示 echo "系统繁忙,请稍后再试"; }
PDO::ATTR_PERSISTENT
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
$pdo = null
<?php class Database { private $pdo; public function __construct() { $this->connect(); } private function connect() { try { $this->pdo = new PDO( 'mysql:host=localhost;dbname=myapp;charset=utf8mb4', 'db_user', 'secure_password', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ] ); } catch (PDOException $e) { die("数据库连接失败: " . $e->getMessage()); } } public function getUser($userId) { $stmt = $this->pdo->prepare("SELECT * FROM users WHERE id = :id"); $stmt->execute([':id' => $userId]); return $stmt->fetch(); } public function insertUser($userData) { $stmt = $this->pdo->prepare(" INSERT INTO users(username, email, created_at) VALUES(:username, :email, NOW()) "); return $stmt->execute([ ':username' => $userData['username'], ':email' => $userData['email'] ]); } } // 使用示例 $db = new Database(); $user = $db->getUser(42);
Q:PDO能防SQL注入吗? A:正确使用预处理语句时可以,但直接拼接SQL仍然危险。
Q:如何获取查询的行数? A:$stmt->rowCount()
,但SELECT结果可能不准确,建议使用COUNT查询。
Q:PDO支持哪些数据库? A:完整列表包括MySQL、PostgreSQL、SQLite、Oracle、SQL Server等。
Q:为什么我的预处理语句很慢? A:检查是否禁用了模拟预处理(PDO::ATTR_EMULATE_PREPARES => false
)
通过本文的全面介绍,您应该已经掌握了PDO的核心用法。在实际开发中,建议将数据库操作封装到单独的类中,以提高代码的可维护性和安全性。 “`
这篇文章约3100字,涵盖了PDO的核心知识点,包括: 1. 基础连接和配置 2. 预处理语句使用 3. 事务处理 4. 结果集操作 5. 性能优化建议 6. 完整封装示例 7. 常见问题解答
采用Markdown格式,包含代码块、表格等元素,便于阅读和理解。可根据需要调整具体细节或补充特定数据库的专有特性。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。