PHP mysqli 实用开发指南

PHP mysqli 实用开发指南

在 PHP 开发中,与 MySQL 数据库交互是最常见的需求之一。

mysqli是 PHP 官方推荐的 MySQL 扩展,它提供了面向对象过程化 两种风格,支持预处理语句(防 SQL 注入)、事务处理等高级特性,完全替代了早已废弃的 mysql 扩展。

一、连接与关闭数据库

面向对象风格:(推荐)

php 复制代码
<?php
// 数据库配置
$host = 'localhost';
$user = 'root';
$password = 'your_password';
$database = 'your_database';
$port = 3306;

// 创建连接
$mysqli = new mysqli($host, $user, $password, $database, $port);

// 检查连接错误
if ($mysqli->connect_error) {
    die('连接失败: ' . $mysqli->connect_error);
}

// 设置字符集(非常重要,防止乱码)
$mysqli->set_charset('utf8mb4');

echo '连接成功!';

// 关闭连接(可选,脚本结束时会自动关闭)
$mysqli->close();
?>

过程化风格

php 复制代码
<?php
$host = 'localhost';
$user = 'root';
$password = 'your_password';
$database = 'your_database';

// 创建连接
$mysqli = mysqli_connect($host, $user, $password, $database);

// 检查连接错误
if (!$mysqli) {
    die('连接失败: ' . mysqli_connect_error());
}

// 设置字符集
mysqli_set_charset($mysqli, 'utf8mb4');

echo '连接成功!';

// 关闭连接
mysqli_close($mysqli);
?>

二、查询数据

方法 说明 返回数据类型
fetch_assoc() 返回关联数组(键名为字段名) array
fetch_row() 返回索引数组(键名为数字索引) array
fetch_array() 返回关联 + 索引数组(默认) array
fetch_object() 返回对象(属性名为字段名) object
php 复制代码
<?php
$mysqli = new mysqli('localhost', 'root', 'pwd', 'test_db');
$mysqli->set_charset('utf8mb4');

// 执行查询
$sql = "SELECT id, username, email FROM users WHERE age > 18";
$result = $mysqli->query($sql);

// 检查是否有结果
if ($result && $result->num_rows > 0) {
    // 1. 使用 fetch_assoc()(推荐,最直观)
    echo "<h3>关联数组方式:</h3>";
    while ($row = $result->fetch_assoc()) {
        echo "ID: " . $row['id'] . " - 用户名: " . $row['username'] . " - 邮箱: " . $row['email'] . "<br>";
    }

    // 2. 使用 fetch_object()(如果你喜欢对象风格)
    // 注意:需要先将结果集指针重置到开头(如果已经遍历过一次)
    $result->data_seek(0);
    echo "<h3>对象方式:</h3>";
    while ($row = $result->fetch_object()) {
        echo "ID: " . $row->id . " - 用户名: " . $row->username . "<br>";
    }
} else {
    echo "没有找到数据";
}

// 释放结果集
$result->free();
$mysqli->close();
?>

三、插入、更新、删除

插入数据(INSERT)

php 复制代码
<?php
$mysqli = new mysqli('localhost', 'root', 'pwd', 'test_db');
$mysqli->set_charset('utf8mb4');

$sql = "INSERT INTO users (username, email, age) VALUES ('张三', 'zhangsan@example.com', 25)";

if ($mysqli->query($sql) === TRUE) {
    // 获取插入的自增 ID(非常常用!)
    $new_id = $mysqli->insert_id;
    echo "数据插入成功,新记录 ID 为: " . $new_id;
} else {
    echo "插入错误: " . $mysqli->error;
}

$mysqli->close();
?>

更新数据(UPDATE)

php 复制代码
<?php
$mysqli = new mysqli('localhost', 'root', 'pwd', 'test_db');
$mysqli->set_charset('utf8mb4');

$sql = "UPDATE users SET age = 26 WHERE username = '张三'";

if ($mysqli->query($sql) === TRUE) {
    // 获取受影响的行数
    echo "数据更新成功,受影响行数: " . $mysqli->affected_rows;
} else {
    echo "更新错误: " . $mysqli->error;
}

$mysqli->close();
?>

删除数据(DELETE)

php 复制代码
<?php
$mysqli = new mysqli('localhost', 'root', 'pwd', 'test_db');
$mysqli->set_charset('utf8mb4');

$sql = "DELETE FROM users WHERE id = 10";

if ($mysqli->query($sql) === TRUE) {
    echo "数据删除成功,受影响行数: " . $mysqli->affected_rows;
} else {
    echo "删除错误: " . $mysqli->error;
}

$mysqli->close();
?>

四、核心重点:预处理语句(防 SQL 注入)

SQL 注入 是最常见的安全漏洞,预处理语句是解决这个问题的最佳方案。

它的原理是:先发送 SQL 模板,再发送参数,数据与逻辑分离,绝对安全。

这样就不怕 1==1 --攻击了!

方法 说明
prepare($sql) 准备 SQL 语句,返回 statement 对象
bind_param() 绑定参数(给占位符赋值)
execute() 执行预处理语句
get_result() 获取结果集(仅 SELECT,需要 mysqlnd 驱动)
bind_result() 绑定结果变量(用于获取 SELECT 数据)
close() 关闭 statement 对象

bind_param() 第一个参数是类型字符串,每个字符对应一个参数的类型:

字符 类型
i integer
d double
s string
b blob

使用预处理查询数据(SELECT):

php 复制代码
<?php
$mysqli = new mysqli('localhost', 'root', 'pwd', 'test_db');
$mysqli->set_charset('utf8mb4');

// SQL 模板,使用 ? 作为占位符
$sql = "SELECT id, username, email FROM users WHERE age > ? AND city = ?";

// 1. 准备语句
$stmt = $mysqli->prepare($sql);

// 2. 绑定参数 (i = int, s = string)
$age = 18;
$city = '北京';
$stmt->bind_param('is', $age, $city); // 注意:变量必须在 bind_param 之前定义

// 3. 执行
$stmt->execute();

// 4. 获取结果(推荐使用 get_result,需要 mysqlnd 驱动)
$result = $stmt->get_result();

if ($result->num_rows > 0) {
    while ($row = $result->fetch_assoc()) {
        echo "ID: " . $row['id'] . " - 用户名: " . $row['username'] . "<br>";
    }
} else {
    echo "没有数据";
}

// 5. 关闭
$stmt->close();
$mysqli->close();
?>

使用预处理插入数据(INSERT):

php 复制代码
<?php
$mysqli = new mysqli('localhost', 'root', 'pwd', 'test_db');
$mysqli->set_charset('utf8mb4');

$sql = "INSERT INTO users (username, email, age) VALUES (?, ?, ?)";

$stmt = $mysqli->prepare($sql);

// 绑定参数
$username = '李四';
$email = 'lisi@example.com';
$age = 30;
$stmt->bind_param('ssi', $username, $email, $age);

if ($stmt->execute()) {
    echo "插入成功,新 ID: " . $stmt->insert_id; // 注意:这里是 $stmt->insert_id
} else {
    echo "插入失败: " . $stmt->error;
}

$stmt->close();
$mysqli->close();
?>

五、事务处理(保证数据一致性)

事务用于确保一组 SQL 操作要么全部成功,要么全部失败(例如:转账操作,A 扣钱和 B 加钱必须同时成功)。

php 复制代码
<?php
$mysqli = new mysqli('localhost', 'root', 'pwd', 'test_db');
$mysqli->set_charset('utf8mb4');

// 关闭自动提交(开启事务)
$mysqli->autocommit(FALSE);

try {
    // 操作 1:A 账户扣 100 元
    $sql1 = "UPDATE accounts SET balance = balance - 100 WHERE id = 1";
    $mysqli->query($sql1);
    if ($mysqli->affected_rows === 0) {
        throw new Exception("A 账户扣款失败");
    }

    // 操作 2:B 账户加 100 元
    $sql2 = "UPDATE accounts SET balance = balance + 100 WHERE id = 2";
    $mysqli->query($sql2);
    if ($mysqli->affected_rows === 0) {
        throw new Exception("B 账户加款失败");
    }

    // 提交事务
    $mysqli->commit();
    echo "转账成功!";
} catch (Exception $e) {
    // 回滚事务
    $mysqli->rollback();
    echo "转账失败: " . $e->getMessage();
}

// 重新开启自动提交
$mysqli->autocommit(TRUE);
$mysqli->close();
?>

六、最佳实践总结

  1. 永远使用面向对象风格:代码更现代,易维护。
  2. 永远使用预处理语句:杜绝 SQL 注入,这是底线。
  3. 永远设置字符集 :使用 utf8mb4(支持 emoji),防止乱码。
  4. 做好错误处理 :不要直接输出 $mysqli->error 到生产环境,应记录日志。
  5. 关闭连接是好习惯:虽然脚本结束会自动关闭,但显式关闭更规范。

掌握以上内容,足以应对 95% 的 PHP 数据库开发场景。如果需要更复杂的功能(如批量插入、多结果集),可以查阅 PHP 官方手册进一步深入。

相关推荐
studyForMokey3 小时前
【Android面试】Handler专题
android·java·面试
Evand J3 小时前
【MATLAB例程】多无人机协同巡逻仿真:基于长机-僚机模型的编队保持与串级PID控制
开发语言·matlab·无人机·控制·pid·串级pid
yoothey3 小时前
我对Java Web开发中多线程的困惑
java·开发语言·前端
周淳APP3 小时前
【React之Hooks原理、组件、状态管理浅谈】
开发语言·前端·javascript
楼田莉子3 小时前
CMake学习:CMake在静态库工程场景上应用
开发语言·c++·后端·学习·软件构建
csbysj20203 小时前
SVG 渐变 - 线性
开发语言
迷藏4943 小时前
**发散创新:用 Rust实现高效共识算法——从 Raft到自研轻量级协议的实战演进**
java·开发语言·rust·共识算法
wuqingshun3141593 小时前
说说你对spring MVC的理解
java·开发语言·jvm