MySQL 连接
PHP 连接到 MySQL
Section titled “PHP 连接到 MySQL”现代 PHP 应用主要使用以下两个扩展与 MySQL 数据库交互:
- MySQLi: 专门为 MySQL 设计的改进扩展。提供面向对象和面向过程两种接口。
- PDO (PHP Data Objects): 一个一致的数据库抽象层,支持多种数据库系统(包括 MySQL)。主要为面向对象接口。
旧的 mysql_* 扩展已被弃用,并且由于存在安全漏洞和缺乏现代功能,不应在新代码中使用。
应该使用 MySQLi 还是 PDO?
Section titled “应该使用 MySQLi 还是 PDO?”选择通常取决于项目需求:
- PDO: 如果你预计将来可能需要切换到其他数据库系统(例如 PostgreSQL、SQLite),则推荐使用。它为不同的数据库提供了统一的 API,使得迁移更容易。它是严格的面向对象。
- MySQLi: 如果你确定应用程序只使用 MySQL,则非常适合。一些开发者可能偏爱它更直接地映射到 MySQL 特有功能,或者喜欢其可选的面向过程风格。
- 两者: 都支持预处理语句(对安全至关重要)、事务和现代 MySQL 功能。
对于大多数新项目来说,因其灵活性和抽象性,PDO 通常更受青睐。
启用 MySQLi 和 PDO_MySQL
Section titled “启用 MySQLi 和 PDO_MySQL”这两个扩展通常包含在 PHP 中,但可能需要手动启用。
- Linux 系统(包管理器): 通常由
php-mysql包提供(该包通常会安装 MySQLi 和 PDO_MySQL)。示例:sudo apt-get install php-mysql或sudo yum install php-mysqlnd。重启你的 Web 服务器/PHP-FPM。 - Windows 系统: 检查你的
php.ini文件。取消注释或添加类似extension=mysqli和extension=pdo_mysql的行。确保extension_dir设置正确。重启你的 Web 服务器。 - 检查: 使用
php -m或phpinfo()来验证mysqli和pdo_mysql是否被列为已启用的模块。
请参阅你的环境文档以获取具体信息。
打开到 MySQL 的连接
Section titled “打开到 MySQL 的连接”在与数据库交互之前,必须建立连接。
最佳实践:安全地存储数据库凭据(例如,使用环境变量或放置在 Web 根目录之外的配置文件),而不是直接写在代码中。
示例:MySQLi(面向对象风格)
Section titled “示例:MySQLi(面向对象风格)”<?php$servername = getenv('DB_HOST') ?: "localhost";$username = getenv('DB_USER') ?: "your_username";$password = getenv('DB_PASS') ?: "your_password";$dbname = getenv('DB_NAME') ?: "myDB";
// 创建连接mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // 将错误报告为异常
try { $conn = new mysqli($servername, $username, $password, $dbname);
// 设置字符集 - 非常重要 $conn->set_charset("utf8mb4");
echo "Connected successfully using MySQLi (OO)"; // 使用 MySQLi (OO) 连接成功
} catch (mysqli_sql_exception $e) { // 处理连接错误 // 在生产环境中应记录错误日志,而不是回显详细信息 error_log("MySQLi Connection Error: " . $e->getMessage()); die("Database connection failed. Please try again later."); // 友好提示用户}
// 连接对象 ($conn) 现在已准备好进行查询// ... 执行查询 ...
// 关闭连接(可选,PHP 在脚本结束时会自动关闭)// $conn->close();?>示例:MySQLi(面向过程风格)
Section titled “示例:MySQLi(面向过程风格)”<?php$servername = getenv('DB_HOST') ?: "localhost";$username = getenv('DB_USER') ?: "your_username";$password = getenv('DB_PASS') ?: "your_password";$dbname = getenv('DB_NAME') ?: "myDB";
// 将错误报告为异常mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try { // 创建连接 $conn = mysqli_connect($servername, $username, $password, $dbname);
// 设置字符集 - 非常重要 mysqli_set_charset($conn, "utf8mb4");
echo "Connected successfully using MySQLi (Procedural)"; // 使用 MySQLi (面向过程) 连接成功
} catch (mysqli_sql_exception $e) { // 处理连接错误 error_log("MySQLi Connection Error: " . $e->getMessage()); die("Database connection failed. Please try again later.");}
// 连接资源 ($conn) 现在已准备好进行查询// ... 执行查询 ...
// 关闭连接(可选)// mysqli_close($conn);?>示例:PDO
Section titled “示例:PDO”<?php$host = getenv('DB_HOST') ?: 'localhost';$db = getenv('DB_NAME') ?: 'myDBPDO';$user = getenv('DB_USER') ?: 'your_username';$pass = getenv('DB_PASS') ?: 'your_password';$charset = 'utf8mb4'; // 推荐的字符集
// Data Source Name (DSN) 数据源名称$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 以异常形式开启错误报告 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 默认获取模式为关联数组 PDO::ATTR_EMULATE_PREPARES => false, // 出于安全和性能考虑禁用模拟];
try { // 创建 PDO 实例 $pdo = new PDO($dsn, $user, $pass, $options); echo "Connected successfully using PDO"; // 使用 PDO 连接成功
} catch (PDOException $e) { // 处理连接错误 error_log("PDO Connection Error: " . $e->getMessage()); // throw new PDOException($e->getMessage(), (int)$e->getCode()); // 或重新抛出异常 die("Database connection failed. Please try again later.");}
// PDO 对象 ($pdo) 现在已准备好进行查询// ... 执行查询 ...
// 关闭连接(可选,会自动发生)// $pdo = null;?>连接示例中的要点:
- 错误处理: 使用
try...catch块是现代方式。MySQLi 需要mysqli_report()才能抛出异常;PDO 则通过ATTR_ERRMODE选项实现。 - 凭据: 通过
getenv()获取凭据是外部配置的一个示例。 - 字符集: 明确将字符集设置为
utf8mb4(通过$conn->set_charset()或在 DSN/选项中设置)对于正确处理各种字符(包括 emoji)至关重要。 - PDO 选项: 推荐将
PDO::ATTR_ERRMODE设置为PDO::ERRMODE_EXCEPTION,设置PDO::ATTR_DEFAULT_FETCH_MODE以方便使用,以及禁用PDO::ATTR_EMULATE_PREPARES。
在典型的 Web 请求场景中,当脚本执行完毕时,PHP 会自动关闭数据库连接。通常无需显式关闭连接。
然而,在长时间运行的脚本或资源受限的环境中,一旦不再需要连接就立即关闭是一个好习惯:
- MySQLi (OO):
$conn->close(); - MySQLi (面向过程):
mysqli_close($conn); - PDO:
$pdo = null;(将对象变量设置为 null 会移除引用,允许 PHP 的垃圾回收器关闭连接)。
上面的示例展示了这些调用通常放置的位置(通常被注释掉了)。