和创建表一样,往数据库里插入数据(INSERT)也是PHP开发中的高频操作。在PHP 5.5之前,很多老程序员用mysql_query()一条一条往里塞数据。但这个函数早已被官方废弃,主要原因还是安全风险和功能缺失。
你现在需要掌握的两种替代方案:
-
mysqli_query() — 配合MySQLi扩展使用
-
PDO::exec() / PDO::prepare() — 配合PDO扩展使用
这篇文章不讲废话,直接以插入记录为实战目标,带你把这几种写法吃透。顺便也会聊一下为什么你该尽早放弃老思路。
1. 插入记录的核心SQL语句:INSERT INTO
不管用什么PHP扩展,最终执行的SQL核心不变:
INSERT INTO 表名 (列1, 列2, 列3) VALUES (值1, 值2, 值3)
专业名词提醒:
-
INSERT:数据操作语言(DML)的一种
-
VALUES:指定要插入的具体数据
-
字符串必须用引号:在SQL中,字符串类型的值要用单引号或双引号包起来
2. 方法一:MySQLi 面向过程写法
这种方式最直白。适合小型脚本或刚刚接触PHP数据库操作的新手。
代码号示例:向员工表插入一条记录
<?php
$host = 'localhost:3306';
$user = 'code_user'; // 生产环境请不要用root
$pass = 'SafePass2026';
$dbname = 'company_db';
// 建立连接
$conn = mysqli_connect($host, $user, $pass, $dbname);
if(!$conn){
die('连接失败:' . mysqli_connect_error());
}
// 插入一条记录(name 和 salary)
$sql = "INSERT INTO emp_basic (name, salary) VALUES ('李明', 7500)";
if(mysqli_query($conn, $sql)){
echo "记录插入成功,新插入的ID为:" . mysqli_insert_id($conn);
} else {
echo "插入失败:" . mysqli_error($conn);
}
mysqli_close($conn);
?>
个人经验分享:
很多人只用mysqli_query()返回true/false就结束了,但其实有一个函数非常实用:mysqli_insert_id()。如果你的表有AUTO_INCREMENT主键(比如id列),这个函数会返回刚插入那行数据生成的自增ID。尤其是在后面要做关联插入(比如用户注册后立刻要往其他表写用户ID)时,这个值必不可少。
为什么早期老代码喜欢用mysql_query插数据?
因为写起来够短。但它不带预处理机制,SQL注入风险极大。上面的示例里,如果$_POST['name']直接拼进SQL,恶意用户就可以通过特殊构造的参数破坏你的数据库。
3. 方法二:MySQLi 面向对象写法
相比面向过程,这种写法结构更清晰。可读性更好,适合中大型项目。
代码号示例:使用面向对象的MySQLi插入更多字段
<?php
$servername = "localhost";
$username = "code_user";
$password = "SafePass2026";
$dbname = "company_db";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("连接失败:" . $conn->connect_error);
}
// 插入更完整的用户资料
$sql = "INSERT INTO users_profile (fullname, email) VALUES ('王芳', 'wang@ebingou.cn')";
if ($conn->query($sql) === TRUE) {
echo "新记录插入成功,ID:" . $conn->insert_id;
} else {
echo "插入出错:" . $conn->error;
}
$conn->close();
?>
个人见解:
面向对象的方式,insert_id是一个属性,写法更统一。而且当项目逐渐变大,你需要封装数据库操作类时,面向对象的风格会更容易集成。
不过这里必须说一句:上面这两个MySQLi示例其实还有改进空间。它们都是直接把变量拼进SQL。真正的项目里,更可靠的做法是使用“预处理语句”。这算是我踩坑多次后养成的习惯。
4. 方法三:PDO 插入记录(推荐方式)
PDO是我个人在生产环境中使用频率较高的方式。它有两个关键优势:
-
支持预处理:从根本上解决SQL注入
-
异常机制:错误处理更清晰
代码号示例:PDO插入数据 + 异常处理
<?php
$servername = "localhost";
$username = "code_user";
$password = "SafePass2026";
$dbname = "company_db_pdo";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 插入数据
$sql = "INSERT INTO users_profile (fullname, email) VALUES ('张立', 'zhang@ebingou.cn')";
$conn->exec($sql);
// 获取之后插入的ID
$last_id = $conn->lastInsertId();
echo "记录插入成功,之后插入的ID:" . $last_id;
} catch(PDOException $e) {
echo "执行失败:" . $e->getMessage();
}
$conn = null;
?>
关于exec()和query()的区别:
-
exec():用于INSERT、UPDATE、DELETE等不返回结果集的SQL,返回值是受影响的行数 -
query():用于SELECT等会返回结果集的SQL
5. 进阶:预处理语句(防SQL注入的关键)
前面提到的示例都是静态SQL。但在Web应用中,用户输入的数据是动态的。这时候如果直接拼SQL,就会产生严重的安全隐患。
下面以PDO预处理为例展示一个更安全的插入写法。这也是本节课程知识要点的核心内容。
// 假设用户通过表单提交了姓名和邮箱
$fullname = $_POST['fullname'];
$email = $_POST['email'];
try {
$conn = new PDO("mysql:host=localhost;dbname=company_db_pdo", "code_user", "SafePass2026");
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 预处理:使用占位符 :name 和 :email
$stmt = $conn->prepare("INSERT INTO users_profile (fullname, email) VALUES (:name, :email)");
// 绑定参数并执行
$stmt->execute([
':name' => $fullname,
':email' => $email
]);
echo "用户 " . $fullname . " 注册成功";
} catch(PDOException $e) {
echo "插入失败:" . $e->getMessage();
}
为什么我不建议在老项目中继续用mysql_query风格插入数据?
-
不支持预处理:一旦字段值里出现单引号、SQL关键字,轻则报错,重则被拖库
-
没有异常机制:错误信息混乱,不利于调试
-
维护成本高:当表结构复杂、字段一多,拼SQL的代码就会变得难以阅读
6. 三种插入方式的适用场景
| 场景 | 推荐方式 | 理由 |
|---|---|---|
| 学习阶段、极简脚本 | MySQLi面向过程 | 代码直观,快速上手 |
| 中小型项目 | MySQLi面向对象 | 结构清晰,便于封装 |
| 新项目、多人协作、注重安全 | PDO + 预处理 | 防注入、支持多数据库、异常处理完善 |
个人主观建议:
如果你是2026年才开始学习PHP,可以直接跳过MySQLi面向过程的写法,从PDO预处理开始练。这不代表MySQLi不能用,而是从成本和收益来看,PDO的学习曲线更值得投入。大多数现在PHP框架(Laravel、ThinkPHP等)底层操作数据库用的也是PDO或基于PDO的封装。
7. 常见问题(个人踩坑记录)
-
插入成功但表里看不到数据:检查你是否在事务(Transaction)中执行了INSERT但没有提交(commit)。
-
中文显示乱码:连接数据库后立即执行
$conn->exec("SET NAMES utf8")。 -
insert_id返回0:检查表中是否有
AUTO_INCREMENT的主键字段。 -
mysqli_query返回false但没有错误信息:检查连接是否还在,或者是否执行了不支持的SQL操作。
插入数据是CRUD中非常基础但高频的操作。从废弃的mysql_query()到mysqli_query()再到PDO,每一次演进都更重视安全性和可维护性。写代码时不光要“跑通”,更要考虑半年后别人(包括你自己)还能不能读懂和修改。希望这篇文章能帮你少走一些弯路。