您好,登录后才能下订单哦!
# 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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。