PHP 7.0+ 中 mysql_connect() 和 mysql_query() 已被彻底移除,必须改用 mysqli 或 PDO;推荐 PDO 因其支持预处理、多数据库及异常模式,连接需检查返回值,查询须用 prepare/execute 防注入,且注意语句类型对应不同返回值与处理方式。

PHP里怎么安全地调用数据库操作函数
直接用 mysql_connect() 或 mysql_query() 会报错甚至被拒绝执行——这些函数在 PHP 7.0+ 已被彻底移除,不是“不推荐”,是根本不存在。现在必须用 PDO 或 mysqli,且优先选 PDO,因为支持预处理、多数据库切换、异常模式更可控。
常见错误现象:Fatal error: Uncaught Error: Call to undefined function mysql_connect();或者用 mysqli_connect() 却没检查返回值,导致后续 mysqli_query() 在 false 上调用,直接崩溃。
- 连接时务必检查返回值:
$conn = mysqli_connect($host, $user, $pass, $db); if (!$conn) { die('连接失败: ' . mysqli_connect_error()); } - 查询前开启异常模式(PDO):
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);,否则错误静默失败 - 不要拼接 SQL 字符串传参,哪怕只是整数 ID——用
prepare()+execute()是唯一靠谱路径
为什么 mysqli_query() 有时返回 false,有时又返回结果集
它取决于你执行的是什么语句:SELECT、SHOW、DESCRIBE 这类查数据的,返回 mysqli_result 对象;而 INSERT、UPDATE、DELETE、CREATE 等则返回 true(成功)或 false(失败)。很多人卡在这儿,以为 mysqli_query() 总该有“行数”可读,结果对 INSERT 调用 mysqli_num_rows(),得到警告甚至 NULL。
-
INSERT后想取自增 ID?用mysqli_insert_id($conn),不是从查询结果里捞 -
UPDATE成功但影响 0 行?mysqli_affected_rows($conn)返回 0,这不算错,只是条件没匹配上 - 查完必须释放结果集:
mysqli_free_result($result),尤其在循环中反复查,否则内存泄漏明显
用 PDO::prepare() 时占位符写错了会怎样
写成 WHERE id = :id:(多加了冒号)或 WHERE id = ? 却用 bindValue(':id', $val)(类型不匹配),都会导致 PDOStatement::execute() 返回 false,且默认不抛异常。如果没开 PDO::ERRMODE_EXCEPTION,程序就悄无声息跳过,数据没插进去你也发现不了。
立即学习“PHP免费学习笔记(深入)”;
- 命名参数(
:name)必须和bindValue()/bindParam()的第一个参数完全一致,包括大小写 - 问号占位符只能按顺序绑定,不能跳过中间某个,也不能重复用同一个位置
- 绑定字符串时,显式指定类型更稳:
$stmt->bindValue(1, $str, PDO::PARAM_STR),避免 PDO 自动猜错为INT
函数封装时最容易漏掉的清理动作
很多人写个 db_query($sql, $params) 就完事,但 PDOStatement 对象没关闭、长连接没复用、事务没回滚,跑着跑着就卡死或连不上库。尤其是带事务的函数,一旦中间出错没 rollback(),下一次请求可能还在上个未提交的事务里。
- 用
try...catch包住整个事务块,catch里必须$pdo->rollback() - 不要在函数里
new PDO()每次都新建连接,用单例或依赖注入传入已存在的$pdo实例 - 查询结束后,
PDOStatement会自动销毁,但如果你提前unset($stmt)或让它超出作用域,也没问题——重点是别在循环里反复prepare()同一条 SQL
真正麻烦的从来不是“怎么写第一行连接代码”,而是连接要不要持久化、事务边界划在哪、错误到底算不算失败、结果集什么时候释放——这些不写进函数逻辑里,光靠“调用函数”解决不了问题。



















