MySQL连接
PHP与MySQL连接概述
PHP提供了多种方式来连接和操作MySQL数据库。主要的连接方式包括:
- MySQLi扩展(MySQL Improved)
- PDO(PHP Data Objects)
- 传统的MySQL扩展(已废弃,不推荐使用)
在现代PHP开发中,推荐使用PDO或MySQLi扩展,因为它们提供了更好的安全性、性能和功能支持。
MySQLi扩展连接
MySQLi扩展提供了面向对象和面向过程两种编程风格。
面向对象方式连接
<?php
// 数据库连接配置
$host = 'localhost';
$username = 'root';
$password = 'password';
$database = 'student_system';
$port = 3306;
// 创建MySQLi对象
$mysqli = new mysqli($host, $username, $password, $database, $port);
// 检查连接是否成功
if ($mysqli->connect_error) {
die('连接失败: ' . $mysqli->connect_error);
}
echo '数据库连接成功!';
// 设置字符集
$mysqli->set_charset('utf8mb4');
// 关闭连接
$mysqli->close();
?>
面向过程方式连接
<?php
// 数据库连接配置
$host = 'localhost';
$username = 'root';
$password = 'password';
$database = 'student_system';
// 建立连接
$connection = mysqli_connect($host, $username, $password, $database);
// 检查连接
if (!$connection) {
die('连接失败: ' . mysqli_connect_error());
}
echo '数据库连接成功!';
// 设置字符集
mysqli_set_charset($connection, 'utf8mb4');
// 关闭连接
mysqli_close($connection);
?>
PDO连接
PDO是PHP的数据库抽象层,支持多种数据库系统,包括MySQL、PostgreSQL、SQLite等。
基本PDO连接
<?php
// 数据库连接配置
$host = 'localhost';
$dbname = 'student_system';
$username = 'root';
$password = 'password';
$charset = 'utf8mb4';
// DSN(数据源名称)
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
// PDO选项
$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, $username, $password, $options);
echo '数据库连接成功!';
} catch (PDOException $e) {
// 连接失败时捕获异常
die('连接失败: ' . $e->getMessage());
}
// PDO对象会在脚本结束时自动关闭连接
?>
使用配置文件的PDO连接
<?php
// config.php
class Database {
private static $instance = null;
private $pdo;
private $host = 'localhost';
private $dbname = 'student_system';
private $username = 'root';
private $password = 'password';
private $charset = 'utf8mb4';
private function __construct() {
$dsn = "mysql:host={$this->host};dbname={$this->dbname};charset={$this->charset}";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_PERSISTENT => true, // 持久连接
];
try {
$this->pdo = new PDO($dsn, $this->username, $this->password, $options);
} catch (PDOException $e) {
throw new PDOException('数据库连接失败: ' . $e->getMessage());
}
}
// 单例模式
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function getConnection() {
return $this->pdo;
}
// 防止克隆
private function __clone() {}
// 防止反序列化
public function __wakeup() {
throw new Exception("Cannot unserialize singleton");
}
}
// 使用示例
try {
$db = Database::getInstance();
$pdo = $db->getConnection();
echo '数据库连接成功!';
} catch (Exception $e) {
die('连接失败: ' . $e->getMessage());
}
?>
连接参数详解
常用连接参数
// DSN参数说明
$dsn = "mysql:host=localhost;dbname=test;charset=utf8mb4;port=3306";
// 参数说明:
// host - 数据库主机名
// dbname - 数据库名称
// charset - 字符集
// port - 端口号(默认3306)
// socket - Unix套接字路径(可选)
PDO连接选项
$options = [
// 错误处理模式
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 抛出异常
// PDO::ERRMODE_WARNING // 发出警告
// PDO::ERRMODE_SILENT // 静默模式
// 默认获取模式
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 关联数组
// PDO::FETCH_NUM // 数字索引数组
// PDO::FETCH_OBJ // 对象形式
// PDO::FETCH_BOTH // 同时包含关联和数字索引
// 预处理设置
PDO::ATTR_EMULATE_PREPARES => false, // 禁用模拟预处理
// 持久连接
PDO::ATTR_PERSISTENT => true, // 启用持久连接
// 自动提交
PDO::ATTR_AUTOCOMMIT => true, // 自动提交模式
// 连接超时
PDO::ATTR_TIMEOUT => 30, // 连接超时时间(秒)
// 服务器端预处理
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, // 使用缓冲查询
];
连接管理
持久连接
持久连接可以避免每次脚本执行都重新建立数据库连接,提高性能。
<?php
// PDO持久连接
$options = [
PDO::ATTR_PERSISTENT => true,
// 其他选项...
];
$pdo = new PDO($dsn, $username, $password, $options);
// MySQLi持久连接
$mysqli = mysqli_connect('p:' . $host, $username, $password, $database);
?>
连接池
<?php
class ConnectionPool {
private static $pool = [];
private static $maxConnections = 10;
public static function getConnection($config) {
$key = md5(serialize($config));
if (!isset(self::$pool[$key]) || count(self::$pool[$key]) === 0) {
// 创建新连接
$connection = new PDO(
$config['dsn'],
$config['username'],
$config['password'],
$config['options']
);
return $connection;
}
// 从池中获取连接
return array_pop(self::$pool[$key]);
}
public static function releaseConnection($connection, $config) {
$key = md5(serialize($config));
if (!isset(self::$pool[$key])) {
self::$pool[$key] = [];
}
if (count(self::$pool[$key]) < self::$maxConnections) {
array_push(self::$pool[$key], $connection);
}
}
}
?>
错误处理
MySQLi错误处理
<?php
// 面向对象方式的错误处理
try {
$mysqli = new mysqli($host, $username, $password, $database);
if ($mysqli->connect_error) {
throw new Exception('连接失败: ' . $mysqli->connect_error);
}
// 执行查询
$result = $mysqli->query("SELECT * FROM students");
if (!$result) {
throw new Exception('查询失败: ' . $mysqli->error);
}
} catch (Exception $e) {
error_log('数据库错误: ' . $e->getMessage());
// 用户友好的错误信息
die('系统错误,请稍后再试');
}
// 面向过程方式的错误处理
$connection = mysqli_connect($host, $username, $password, $database);
if (!$connection) {
error_log('连接失败: ' . mysqli_connect_error());
die('数据库连接失败');
}
$result = mysqli_query($connection, "SELECT * FROM students");
if (!$result) {
error_log('查询失败: ' . mysqli_error($connection));
die('查询失败');
}
?>
PDO错误处理
<?php
try {
$pdo = new PDO($dsn, $username, $password, $options);
// 设置错误模式为异常
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 执行查询
$stmt = $pdo->prepare("SELECT * FROM students WHERE age > :age");
$stmt->execute(['age' => 18]);
$students = $stmt->fetchAll();
} catch (PDOException $e) {
// 记录错误日志
error_log('数据库错误: ' . $e->getMessage());
// 根据错误类型进行不同处理
switch ($e->getCode()) {
case 1045: // 访问被拒绝
die('数据库认证失败');
case 1049: // 数据库不存在
die('数据库不存在');
case 2002: // 无法连接
die('无法连接到数据库服务器');
default:
die('数据库操作失败');
}
}
?>
连接安全性
使用环境变量存储敏感信息
<?php
// .env 文件
DB_HOST=localhost
DB_NAME=student_system
DB_USER=root
DB_PASS=password
DB_CHARSET=utf8mb4
// PHP代码
class Config {
public static function get($key) {
static $config = null;
if ($config === null) {
$config_file = __DIR__ . '/.env';
if (file_exists($config_file)) {
$lines = file($config_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (strpos($line, '=') !== false) {
list($k, $v) = explode('=', $line, 2);
$config[trim($k)] = trim($v);
}
}
}
}
return $config[$key] ?? null;
}
}
// 使用配置
$host = Config::get('DB_HOST');
$dbname = Config::get('DB_NAME');
$username = Config::get('DB_USER');
$password = Config::get('DB_PASS');
?>
SSL连接
<?php
// SSL连接配置
$ssl_options = [
PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem',
PDO::MYSQL_ATTR_SSL_CERT => '/path/to/client-cert.pem',
PDO::MYSQL_ATTR_SSL_KEY => '/path/to/client-key.pem',
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
];
$options = array_merge($ssl_options, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
try {
$pdo = new PDO($dsn, $username, $password, $options);
echo 'SSL连接成功!';
} catch (PDOException $e) {
die('SSL连接失败: ' . $e->getMessage());
}
?>
性能优化
连接优化建议
- 使用持久连接:减少连接建立开销
- 合理设置超时时间:避免长时间等待
- 使用连接池:管理多个连接
- 及时关闭连接:释放资源
- 批量操作:减少数据库往返次数
示例:优化的数据库连接类
<?php
class OptimizedDatabase {
private $pdo;
private $config;
private $isConnected = false;
public function __construct($config) {
$this->config = $config;
}
// 延迟连接
public function connect() {
if ($this->isConnected) {
return $this->pdo;
}
$dsn = "mysql:host={$this->config['host']};dbname={$this->config['dbname']};charset={$this->config['charset']}";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_TIMEOUT => 30,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false,
];
try {
$this->pdo = new PDO($dsn, $this->config['username'], $this->config['password'], $options);
$this->isConnected = true;
// 设置SQL模式
$this->pdo->exec("SET sql_mode='STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'");
} catch (PDOException $e) {
throw new Exception('数据库连接失败: ' . $e->getMessage());
}
return $this->pdo;
}
// 检查连接状态
public function isConnected() {
return $this->isConnected && $this->pdo !== null;
}
// 重新连接
public function reconnect() {
$this->disconnect();
return $this->connect();
}
// 断开连接
public function disconnect() {
if ($this->isConnected) {
$this->pdo = null;
$this->isConnected = false;
}
}
// 获取连接
public function getConnection() {
if (!$this->isConnected) {
$this->connect();
}
return $this->pdo;
}
// 析构函数
public function __destruct() {
$this->disconnect();
}
}
?>
调试和监控
连接状态检查
<?php
// MySQLi连接状态检查
if ($mysqli->ping()) {
echo "连接正常";
} else {
echo "连接已断开,尝试重新连接...";
if (!$mysqli->real_connect($host, $username, $password, $database)) {
die("重新连接失败");
}
}
// PDO连接状态检查
try {
$stmt = $pdo->query("SELECT 1");
echo "连接正常";
} catch (PDOException $e) {
echo "连接已断开: " . $e->getMessage();
}
?>
连接日志记录
<?php
class DatabaseLogger {
private static $logFile = 'database_connections.log';
public static function logConnection($host, $username, $status, $message = '') {
$timestamp = date('Y-m-d H:i:s');
$ip = $_SERVER['REMOTE_ADDR'] ?? 'CLI';
$logEntry = sprintf(
"[%s] IP: %s | Host: %s | User: %s | Status: %s | Message: %s\n",
$timestamp, $ip, $host, $username, $status, $message
);
file_put_contents(self::$logFile, $logEntry, FILE_APPEND | LOCK_EX);
}
}
// 使用示例
try {
$pdo = new PDO($dsn, $username, $password, $options);
DatabaseLogger::logConnection($host, $username, 'SUCCESS');
} catch (PDOException $e) {
DatabaseLogger::logConnection($host, $username, 'FAILED', $e->getMessage());
throw $e;
}
?>
总结
在本节中,我们学习了PHP与MySQL数据库连接的各个方面:
- 连接方式:MySQLi和PDO两种主要连接方式
- 配置管理:数据库连接参数和选项设置
- 错误处理:连接和操作中的错误处理机制
- 安全性:SSL连接和环境变量管理
- 性能优化:持久连接、连接池和延迟连接
- 监控调试:连接状态检查和日志记录
选择合适的连接方式和配置对于构建高性能、安全可靠的PHP应用程序至关重要。在现代开发中,推荐使用PDO作为主要的数据库连接方式,因为它提供了更好的抽象性、安全性和可移植性。