
1. PHP与MySQL数据库交互基础PHP作为服务端脚本语言与MySQL数据库的配合堪称Web开发领域的经典组合。我至今记得2003年第一次用mysql_connect()成功连接数据库时的兴奋感——虽然现在这套扩展早已被淘汰但这种后端与数据库的交互模式至今仍是动态网站的核心。1.1 现代PHP数据库交互演进从早期的mysql扩展到后来的mysqli再到现在的PDOPHP Data ObjectsPHP操作数据库的方式经历了三次重大迭代mysql扩展已废弃PHP 5.5.0起被标记为废弃PHP 7.0.0中彻底移除mysqli扩展支持面向对象和面向过程两种写法提供预处理语句支持PDO抽象层支持多种数据库的统一接口具备更好的安全性和可移植性重要提示新项目绝对不要使用mysql_*系列函数它们存在SQL注入风险且不再维护。本文示例将基于PDO实现。1.2 基础连接配置建立数据库连接是操作的第一步。以下是PDO的标准连接方式?php $host localhost; $dbname test_db; $username db_user; $password secure_password; try { $pdo new PDO(mysql:host$host;dbname$dbname;charsetutf8mb4, $username, $password, [ PDO::ATTR_ERRMODE PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE PDO::FETCH_ASSOC ]); } catch (PDOException $e) { die(数据库连接失败: . $e-getMessage()); }关键参数说明charsetutf8mb4支持完整的Unicode字符集包括emojiERRMODE_EXCEPTION让PDO抛出异常而非返回falseFETCH_ASSOC默认返回关联数组而非同时包含索引和关联键的混合数组2. 数据库增删改查(CRUD)实现2.1 数据插入(Create)安全的插入操作应该使用预处理语句$stmt $pdo-prepare(INSERT INTO users (username, email, created_at) VALUES (:username, :email, NOW())); $data [ :username php_lover, :email contactexample.com ]; try { $stmt-execute($data); $lastInsertId $pdo-lastInsertId(); echo 新记录ID: $lastInsertId; } catch (PDOException $e) { echo 插入失败: . $e-getMessage(); }注意事项表字段名不要用反引号包裹除非是MySQL保留字日期时间建议让MySQL生成如NOW()始终捕获PDOException处理潜在错误2.2 数据查询(Read)2.2.1 基础查询$stmt $pdo-query(SELECT id, username FROM users LIMIT 10); $users $stmt-fetchAll(); foreach ($users as $user) { echo ID: {$user[id]}, 用户名: {$user[username]}\n; }2.2.2 带条件的预处理查询$minId 100; $stmt $pdo-prepare(SELECT * FROM users WHERE id ? AND active 1); $stmt-execute([$minId]); while ($row $stmt-fetch()) { // 处理每行数据 }性能技巧大数据集查询使用fetch()逐行处理而非fetchAll()只SELECT需要的字段避免SELECT *复杂查询善用EXPLAIN分析执行计划2.3 数据更新(Update)$stmt $pdo-prepare(UPDATE users SET last_login NOW(), login_count login_count 1 WHERE id :id); $stmt-execute([:id $userId]); $affectedRows $stmt-rowCount(); echo 更新了 $affectedRows 条记录;安全提示确保WHERE条件足够精确避免意外更新大量记录2.4 数据删除(Delete)$stmt $pdo-prepare(DELETE FROM temp_logs WHERE created_at DATE_SUB(NOW(), INTERVAL 30 DAY)); $stmt-execute(); if ($stmt-rowCount() 0) { echo 删除了 {$stmt-rowCount()} 条旧日志; } else { echo 没有符合条件的记录被删除; }重要原则生产环境删除前务必先备份考虑使用软删除标记is_deleted字段替代物理删除大表删除分批进行避免锁表3. 高级操作与性能优化3.1 事务处理try { $pdo-beginTransaction(); // 操作1 $stmt1 $pdo-prepare(UPDATE accounts SET balance balance - ? WHERE user_id ?); $stmt1-execute([$amount, $fromUserId]); // 操作2 $stmt2 $pdo-prepare(UPDATE accounts SET balance balance ? WHERE user_id ?); $stmt2-execute([$amount, $toUserId]); $pdo-commit(); echo 转账成功; } catch (Exception $e) { $pdo-rollBack(); echo 转账失败: . $e-getMessage(); }3.2 批量操作// 批量插入 $data [ [用户1, user1test.com], [用户2, user2test.com], // 更多数据... ]; $pdo-beginTransaction(); $stmt $pdo-prepare(INSERT INTO users (username, email) VALUES (?, ?)); foreach ($data as $row) { $stmt-execute($row); } $pdo-commit();性能对比单条插入1000条约2.3秒事务批量插入1000条约0.15秒多值INSERT语法约0.08秒3.3 预处理语句复用$stmt $pdo-prepare(INSERT INTO log (message, level) VALUES (?, ?)); // 多次执行同一预处理语句 $stmt-execute([调试信息, debug]); $stmt-execute([警告信息, warning]); $stmt-execute([错误信息, error]);4. 安全防护与常见问题4.1 SQL注入防御危险写法// 永远不要这样写 $sql SELECT * FROM users WHERE username {$_GET[user]};正确做法$stmt $pdo-prepare(SELECT * FROM users WHERE username ?); $stmt-execute([$_GET[user]]);4.2 常见错误处理连接问题错误信息SQLSTATE[HY000] [2002] Connection refused检查项MySQL服务是否运行连接地址是否正确防火墙是否放行3306端口字符编码问题现象中文显示为乱码解决方案连接字符串添加charsetutf8mb4确认表字段字符集为utf8mb4HTML页面设置meta charsetUTF-84.3 连接池考虑PHP本身是无共享架构传统连接池方案较少。替代方案持久连接慎用new PDO(mysql:host$host;dbname$dbname, $user, $pass, [ PDO::ATTR_PERSISTENT true ]);使用中间件MySQL RouterProxySQL应用层连接管理5. 现代开发实践5.1 使用Query Builder// 使用Laravel的查询构造器示例 $users DB::table(users) -select(name, email) -where(active, 1) -orderBy(name) -limit(10) -get();优势链式调用更直观自动参数绑定防注入数据库无关的语法5.2 ORM实践// Laravel Eloquent示例 class User extends Model { protected $table users; } // 查询 $user User::where(email, testexample.com)-first(); // 新建 $newUser new User; $newUser-name John; $newUser-save();5.3 数据库迁移// Laravel迁移文件示例 Schema::create(users, function (Blueprint $table) { $table-id(); $table-string(name); $table-string(email)-unique(); $table-timestamp(email_verified_at)-nullable(); $table-timestamps(); });6. 性能监控与调试6.1 查询日志分析启用慢查询日志-- 在MySQL配置文件中设置 slow_query_log 1 slow_query_log_file /var/log/mysql/mysql-slow.log long_query_time 16.2 EXPLAIN使用$stmt $pdo-prepare(EXPLAIN SELECT * FROM users WHERE age ?); $stmt-execute([18]); $explanation $stmt-fetchAll(); print_r($explanation);关键指标typeALL(全表扫描)应尽量避免possible_keys可能使用的索引rows预估检查的行数6.3 PHP调试工具Xdebug提供SQL查询分析Tideways应用性能监控Blackfire专业的PHP性能分析工具7. 实际项目经验分享7.1 分页查询优化基础分页性能差SELECT * FROM large_table LIMIT 1000000, 20优化方案SELECT * FROM large_table WHERE id ? -- 上次看到的最后ID ORDER BY id LIMIT 207.2 大数据导出处理内存优化技巧// 设置不缓冲查询结果 $pdo-setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $stmt $pdo-query(SELECT * FROM huge_table); header(Content-Type: text/csv); $out fopen(php://output, w); while ($row $stmt-fetch()) { fputcsv($out, $row); // 定期刷新输出缓冲 if ($rowCount % 1000 0) { ob_flush(); flush(); } } fclose($out);7.3 连接管理最佳实践及时关闭连接$pdo null; // 显式关闭连接超时设置new PDO(..., [ PDO::ATTR_TIMEOUT 5, // 秒 ]);连接失败重试$maxRetries 3; $retryDelay 1; // 秒 for ($i 0; $i $maxRetries; $i) { try { $pdo new PDO(...); break; } catch (PDOException $e) { if ($i $maxRetries - 1) throw $e; sleep($retryDelay); $retryDelay * 2; // 指数退避 } }