// 数据库参数
$host = 'localhost';
$username = 'root';
$password = '';
$database = 'test_db';
// 创建连接
$conn = new mysqli($host, $username, $password, $database);
// 检查连接是否成功
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
echo "数据库连接成功!";
// 执行查询示例
$sql = "SELECT id, name FROM users";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . ",姓名: " . $row["name"];
}
} else {
echo "没有查询到数据";
}
// 关闭连接
$conn->close();
?>
$host = 'localhost';
$username = 'root';
$password = '';
$database = 'test_db';
// 创建连接
$conn = mysqli_connect($host, $username, $password, $database);
// 检查连接
if (!$conn) {
die("连接失败: " . mysqli_connect_error());
}
echo "数据库连接成功!";
// 执行查询示例
$sql = "SELECT id, name FROM users";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
while ($row = mysqli_fetch_assoc($result)) {
echo "ID: " . $row["id"] . ",姓名: " . $row["name"];
}
}
// 关闭连接
mysqli_close($conn);
?>
$host = 'localhost';
$database = 'test_db';
$username = 'root';
$password = '';
try {
// 创建 PDO 连接
$conn = new PDO("mysql:host=$host;dbname=$database", $username, $password);
// 设置错误模式为异常捕获
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "数据库连接成功!";
// 执行查询示例(使用预处理语句防注入)
$sql = "SELECT id, name FROM users";
$stmt = $conn->prepare($sql);
$stmt->execute();
// 获取结果
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($result as $row) {
echo "ID: " . $row["id"] . ",姓名: " . $row["name"];
}
} catch (PDOException $e) {
die("连接失败: " . $e->getMessage());
}
// 关闭连接(PDO 自动管理)
$conn = null;
?>
防止 SQL 注入
使用预处理语句(如 $stmt->prepare()
+ bindParam
或 execute([参数])
)。
示例(PDO 预处理):
$stmt = $conn->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':email', $email);
$stmt->execute();
错误处理
$conn->connect_error
或 mysqli_connect_error()
。try...catch
+ setAttribute
)。关闭连接
$conn->close()
或 mysqli_close($conn)
。$conn = null
。连接失败可能原因
php.ini
)启用扩展
在 php.ini
中取消注释:
;extension=mysqli
;extension=pdo_mysql
重启 Web 服务器生效。
// 准备预处理语句
$stmt = $conn->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->bind_param("ss", $name, $email); // "ss" 表示两个字符串参数
// 设置参数并执行
$name = "张三";
$email = "[email protected]";
$stmt->execute();
echo "插入成功,ID: " . $stmt->insert_id;
$stmt->close();
try {
$sql = "INSERT INTO users (name, email) VALUES (:name, :email)";
$stmt = $conn->prepare($sql);
// 绑定参数并执行
$stmt->execute([
':name' => '李四',
':email' => '[email protected]'
]);
echo "插入成功,ID: " . $conn->lastInsertId();
} catch (PDOException $e) {
echo "错误: " . $e->getMessage();
}
$sql = "SELECT id, name, email FROM users";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
echo "ID: {$row['id']}, 姓名: {$row['name']}, 邮箱: {$row['email']}
";
}
} else {
echo "没有数据";
}
$result->free(); // 释放结果集
try {
$stmt = $conn->query("SELECT id, name, email FROM users");
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($results as $row) {
echo "ID: {$row['id']}, 姓名: {$row['name']}, 邮箱: {$row['email']}
";
}
} catch (PDOException $e) {
echo "错误: " . $e->getMessage();
}
$stmt = $conn->prepare("UPDATE users SET email = ? WHERE id = ?");
$stmt->bind_param("si", $email, $id); // "si" 表示字符串和整数
$email = "[email protected]";
$id = 1;
$stmt->execute();
echo "更新了 {$stmt->affected_rows} 条记录";
$stmt->close();
try {
$sql = "UPDATE users SET email = :email WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->execute([
':email' => '[email protected]',
':id' => 1
]);
echo "更新了 {$stmt->rowCount()} 条记录";
} catch (PDOException $e) {
echo "错误: " . $e->getMessage();
}
$stmt = $conn->prepare("DELETE FROM users WHERE id = ?");
$stmt->bind_param("i", $id); // "i" 表示整数
$id = 2;
$stmt->execute();
echo "删除了 {$stmt->affected_rows} 条记录";
$stmt->close();
try {
$sql = "DELETE FROM users WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->execute([':id' => 3]);
echo "删除了 {$stmt->rowCount()} 条记录";
} catch (PDOException $e) {
echo "错误: " . $e->getMessage();
}
始终使用预处理语句
错误处理
$conn->error
,PDO 使用 try...catch
捕获异常。关闭连接
// MySQLi
$conn->close();
// PDO
$conn = null;
验证输入数据
filter_var()
验证邮箱、URL 等格式。$id > 0
)。1. 连接数据库 → 2. 准备SQL语句 → 3. 绑定参数 → 4. 执行操作 → 5. 处理结果 → 6. 关闭连接
使用 ORM 框架
如 Laravel 的 Eloquent 或 Doctrine,简化数据库操作。
事务处理
对于多个关联操作,使用事务保证数据一致性:
// PDO 事务示例
$conn->beginTransaction();
try {
$conn->exec("UPDATE account SET balance = balance - 100 WHERE id = 1");
$conn->exec("UPDATE account SET balance = balance + 100 WHERE id = 2");
$conn->commit();
} catch (Exception $e) {
$conn->rollBack();
echo "事务失败: " . $e->getMessage();
}
OOP(面向对象编程,Object-Oriented Programming) 是一种程序设计思想和方法,它把数据和对数据的操作组织成对象(Object),通过对象之间的交互来完成程序设计。
$mysqli = new mysqli('localhost', 'dbuser', 'dbpass', 'dbname');
if ($mysqli->connect_errno) {
throw new Exception('数据库连接失败:' . $mysqli->connect_error);
}
$mysqli->set_charset('utf8mb4');
$sql = "SELECT id, username, email FROM users WHERE status = 1 AND is_deleted = 0 ORDER BY created_at DESC LIMIT 10";
$result = $mysqli->query($sql);
if (!$result) {
throw new Exception('查询失败:' . $mysqli->error);
}
$data = [];
while ($row = $result->fetch_assoc()) {
$data[] = $row;
}
$result->free();
// 返回数据
return $data;
fetch_assoc()
拼到数组里WHERE
、ORDER BY
、LIMIT
都要标准化生产环境绝对禁止拼接变量,必须用预处理。
$stmt = $mysqli->prepare("SELECT id, username, email FROM users WHERE username LIKE CONCAT('%', ?, '%') AND status = 1 LIMIT 20");
if (!$stmt) {
throw new Exception('预处理失败:' . $mysqli->error);
}
$keyword = 'alice'; // 搜索关键词
$stmt->bind_param('s', $keyword);
$stmt->execute();
$result = $stmt->get_result();
$data = [];
while ($row = $result->fetch_assoc()) {
$data[] = $row;
}
$stmt->close();
return $data;
prepare
+ bind_param
) 必须使用CONCAT('%', ?, '%')
写法如果只查一行,可以直接用 fetch_assoc()
拿一次。
php复制编辑$stmt = $mysqli->prepare("SELECT id, username, email FROM users WHERE id = ?");
$stmt->bind_param('i', $user_id);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
$stmt->close();
// 检查是否查到
if (!$user) {
throw new Exception('用户不存在');
}
return $user;
fetch_assoc()
只取一行,后面不用循环分页查询是非常常见需求,要返回数据和总数。
$page = 1;
$page_size = 10;
$offset = ($page - 1) * $page_size;
// 1. 查询数据
$stmt = $mysqli->prepare("SELECT id, username, email FROM users WHERE status = 1 LIMIT ?, ?");
$stmt->bind_param('ii', $offset, $page_size);
$stmt->execute();
$result = $stmt->get_result();
$list = [];
while ($row = $result->fetch_assoc()) {
$list[] = $row;
}
$stmt->close();
// 2. 查询总条数
$sql_total = "SELECT COUNT(*) AS total FROM users WHERE status = 1";
$res_total = $mysqli->query($sql_total);
$total_row = $res_total->fetch_assoc();
$total = (int)$total_row['total'];
$res_total->free();
// 返回分页结果
return [
'list' => $list,
'total' => $total
];
有些条件是用户输入的,要动态拼条件,但还要防注入。常规做法是动态构造 SQL + 参数绑定。
$conditions = [];
$params = [];
$types = '';
// 假设有用户搜索过滤
if (!empty($filter['username'])) {
$conditions[] = "username LIKE CONCAT('%', ?, '%')";
$params[] = $filter['username'];
$types .= 's';
}
if (isset($filter['status'])) {
$conditions[] = "status = ?";
$params[] = (int)$filter['status'];
$types .= 'i';
}
$where = $conditions ? 'WHERE ' . implode(' AND ', $conditions) : '';
$sql = "SELECT id, username, email FROM users $where ORDER BY created_at DESC LIMIT 20";
$stmt = $mysqli->prepare($sql);
if ($params) {
$stmt->bind_param($types, ...$params);
}
$stmt->execute();
$result = $stmt->get_result();
$data = [];
while ($row = $result->fetch_assoc()) {
$data[] = $row;
}
$stmt->close();
return $data;
$types
也要跟着参数增长方面 | 要点 |
---|---|
查询数据 | query 或 prepare + get_result |
查询多行 | while(fetch_assoc) |
查询单行 | fetch_assoc 直接用 |
分页查询 | 两次查询:数据和总数分开 |
防SQL注入 | 预处理 + bind_param |
动态条件 | 组装 WHERE 和 参数,分离绑定 |
稳定性保障 | 任何 query 或 prepare 后必须判断成功 |
字符集设置 | $mysqli->set_charset('utf8mb4') 避免乱码 |
创建连接:
// 面向对象
$mysqli = new mysqli("localhost", "user", "password", "database", 3306);
// 过程式
$link = mysqli_connect("localhost", "user", "password", "database", 3306);
false
,但若启用 MYSQLI_REPORT_STRICT
模式,会抛出 mysqli_sql_exception
。检查连接错误:
// 面向对象
if ($mysqli->connect_errno) {
die("连接失败: " . $mysqli->connect_error);
}
// 过程式
if (mysqli_connect_errno()) {
die("连接失败: " . mysqli_connect_error());
}
关闭连接:
$mysqli->close(); // 面向对象
mysqli_close($link); // 过程式
执行普通查询:
// 面向对象
$result = $mysqli->query("SELECT * FROM users");
// 过程式
$result = mysqli_query($link, "SELECT * FROM users");
mysqli_result
对象。true
。false
(或抛出异常)。获取结果数据:
// 获取关联数组
while ($row = $result->fetch_assoc()) {
echo $row["name"];
}
// 或直接获取所有数据
$data = $result->fetch_all(MYSQLI_ASSOC);
步骤:prepare()
→ bind_param()
→ execute()
→ get_result()
。
$stmt = $mysqli->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$name = "Alice";
$email = "[email protected]";
// 绑定参数(类型标识符:s=string, i=int, d=double, b=blob)
$stmt->bind_param("ss", $name, $email);
// 执行
$stmt->execute();
// 获取插入的 ID
$inserted_id = $stmt->insert_id;
// 关闭预处理语句
$stmt->close();
开启事务:
$mysqli->begin_transaction();
try {
$mysqli->query("UPDATE account SET balance = balance - 100 WHERE user_id = 1");
$mysqli->query("UPDATE account SET balance = balance + 100 WHERE user_id = 2");
$mysqli->commit(); // 提交事务
} catch (mysqli_sql_exception $e) {
$mysqli->rollback(); // 回滚
echo "事务失败: " . $e->getMessage();
}
启用严格异常模式:
$driver = new mysqli_driver();
$driver->report_mode = MYSQLI_REPORT_STRICT | MYSQLI_REPORT_ERROR;
捕获异常:
try {
$mysqli->query("INVALID SQL");
} catch (mysqli_sql_exception $e) {
echo "错误信息: " . $e->getMessage();
echo "错误代码: " . $e->getCode();
}
参数类型检查:
例如 mysqli_query($link, 123)
中的第二个参数必须为字符串,否则抛出 TypeError
。
// PHP 8.0 会报错,PHP 7.x 仅警告
$mysqli->query(123); // 错误:参数必须为字符串
mysqli::get_client_info()
(无参数调用)需改为 mysqli_get_client_info()
。mysqli_bind_param()
和 mysqli_bind_result()
已移除,仅保留 mysqli_stmt_bind_param()
。函数 | 用途 | 示例 |
---|---|---|
mysqli_connect() |
建立数据库连接 | $link = mysqli_connect(...) |
mysqli_query() |
执行 SQL 查询 | $result = mysqli_query($link, $sql) |
mysqli_prepare() |
创建预处理语句 | $stmt = mysqli_prepare($link, $sql) |
mysqli_stmt_bind_param() |
绑定预处理语句参数 | mysqli_stmt_bind_param($stmt, "si", ...) |
mysqli_fetch_assoc() |
获取关联数组结果 | $row = mysqli_fetch_assoc($result) |
mysqli_insert_id() |
获取最后插入的 ID | $id = mysqli_insert_id($link) |
mysqli_affected_rows() |
获取受影响的行数 | $count = mysqli_affected_rows($link) |
mysqli_real_escape_string() |
转义字符串(用于非预处理语句) | $safe = mysqli_real_escape_string($link, $input) |
始终使用预处理语句:避免 SQL 注入,尤其是处理用户输入时。
启用异常模式:
$driver = new mysqli_driver();
$driver->report_mode = MYSQLI_REPORT_STRICT | MYSQLI_REPORT_ERROR;
关闭调试信息:生产环境中隐藏数据库错误细节,记录到日志文件。
资源释放:及时关闭 mysqli_result
和预处理语句对象。
/student_manager
├── index.php # 显示学生列表
├── create.php # 添加新学生
├── edit.php # 编辑学生信息
├── delete.php # 删除学生
├── config.php # 数据库配置
└── style.css # 简单样式
表名:students
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
age INT NOT NULL
);
config.php
)
// 数据库配置
$host = 'localhost';
$user = 'root';
$password = '123456';
$database = 'student_db';
// 创建连接
$mysqli = new mysqli($host, $user, $password, $database);
// 检查连接
if ($mysqli->connect_error) {
die("连接失败: " . $mysqli->connect_error);
}
// 设置字符集
$mysqli->set_charset('utf8mb4');
?>
index.php
)prepare($query);
$search_term = "%$search%";
$stmt->bind_param('s', $search_term);
} else {
$stmt = $mysqli->prepare($query);
}
$stmt->execute();
$result = $stmt->get_result();
?>
学生管理系统
create.php
)prepare("INSERT INTO students (name, email, age) VALUES (?, ?, ?)");
$stmt->bind_param('ssi', $name, $email, $age);
if ($stmt->execute()) {
header('Location: index.php'); // 添加成功跳转
exit;
} else {
$error = "添加失败: " . $stmt->error;
}
}
?>
添加学生
添加新学生
= $error ?>
edit.php
)prepare("SELECT * FROM students WHERE id = ?");
$stmt->bind_param('i', $id);
$stmt->execute();
$student = $stmt->get_result()->fetch_assoc();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'];
$email = $_POST['email'];
$age = $_POST['age'];
$stmt = $mysqli->prepare("UPDATE students SET name=?, email=?, age=? WHERE id=?");
$stmt->bind_param('ssii', $name, $email, $age, $id);
if ($stmt->execute()) {
header('Location: index.php'); // 更新成功跳转
exit;
} else {
$error = "更新失败: " . $stmt->error;
}
}
?>
编辑学生
编辑学生信息
= $error ?>
delete.php
)
include 'config.php';
if (isset($_GET['id'])) {
$id = $_GET['id'];
$stmt = $mysqli->prepare("DELETE FROM students WHERE id = ?");
$stmt->bind_param('i', $id);
if ($stmt->execute()) {
header('Location: index.php'); // 删除成功跳转
} else {
die("删除失败: " . $stmt->error);
}
}
?>
prepare
+ bind_param
处理。htmlspecialchars()
转义所有动态输出。required
属性确保必填字段。$_SERVER['REQUEST_METHOD']
防止直接访问。