在workerman中实现mysql长连接,核心做法是复用pdo或mysqli实例,避免每次请求都建立新连接。具体而言,应在worker进程启动时初始化数据库连接对象,并将其绑定到当前进程上下文(如静态变量或自定义属性),随后在所有业务逻辑中直接使用该实例进行查询。这样做能显著减少tcp握手和认证开销,提升高并发下的响应速度。需要注意的是,由于workerman是多进程模型,每个worker进程必须拥有独立的连接实例,严禁跨进程共享同一个pdo对象,否则会导致严重的并发冲突和数据错乱。

如何确保连接在Worker生命周期内持续有效
要确保连接在Worker整个生命周期内有效,关键在于利用onWorkerStart回调进行初始化,并处理连接断开后的自动重连机制。Workerman的Worker进程可能会因为超时、信号或异常而重启,因此不能假设连接永远在线。最佳实践是在onWorkerStart中创建PDO实例,并在每次执行SQL前检查连接状态。如果检测到连接失效(例如通过ping()方法或捕获异常),则重新建立连接。这种“懒加载”或“即时检查”策略既保证了连接的持久性,又避免了因网络波动导致的静默失败。

<?php use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
class DatabaseManager {
public static $pdo = null;
public static function init() {
if (self::$pdo === null) {
$dsn = 'mysql:host=127.0.0.1;dbname=test;charset=utf8mb4';
$user = 'root';
$pass = 'password';
try {
self::$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
} catch (PDOException $e) {
error_log("DB Connection Failed: " . $e->getMessage());
}
}
}
public static function query($sql, $params = []) {
// 检查连接是否存活,若断开则重建
if (!self::$pdo || !self::$pdo->ping()) {
self::$pdo = null;
self::init();
}
try {
$stmt = self::$pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
} catch (PDOException $e) {
error_log("Query Error: " . $e->getMessage());
return [];
}
}
}
$worker = new Worker('tcp://0.0.0.0:1234');
$worker->onWorkerStart = function($worker) {
DatabaseManager::init();
};
$worker->onMessage = function($connection, $data) {
$result = DatabaseManager::query("SELECT * FROM users WHERE id = ?", [1]);
$connection->send(json_encode($result));
};
Worker::runAll();
多进程环境下如何避免连接冲突
在多进程环境下,避免连接冲突的根本原则是“一进程一连接”。Workerman默认启动多个Worker进程,每个进程都有独立的内存空间。如果在类中定义静态变量来存储PDO实例,必须确保该静态变量在每个进程启动时被正确初始化,而不是在主进程(Master)中初始化后被子进程继承。上述代码示例中,DatabaseManager::init()被放置在onWorkerStart回调中,这正是为了在每个子进程启动时单独创建连接。此外,应避免使用全局单例模式直接实例化数据库连接,除非你能保证该单例在进程 fork 之后被重置。对于更复杂的场景,可以使用ConnectionPool思想,但基础层面只需确保每个Worker持有自己的PDO引用即可。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。

<?php // 验证多进程隔离的代码片段
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
class ProcessSafeDB {
public static $instanceId = null;
public static function getInstance() {
if (self::$instanceId === null) {
// 每个进程首次调用时生成唯一ID并建立连接
self::$instanceId = getmypid() . '_' . uniqid();
echo "Process " . getmypid() . " initialized DB instance: " . self::$instanceId . PHP_EOL;
// 实际这里应返回 PDO 对象
}
return self::$instanceId;
}
}
$worker = new Worker('text://0.0.0.0:2345');
$worker->count = 2; // 启动2个Worker进程
$worker->onWorkerStart = function($worker) {
$id = ProcessSafeDB::getInstance();
// 模拟后续操作
};
$worker->onMessage = function($connection, $msg) {
$id = ProcessSafeDB::getInstance();
$connection->send("Current Instance: " . $id);
};
Worker::runAll();
当MySQL服务器重启后连接池如何处理断连
当MySQL服务器重启或网络闪断时,原有的长连接会变为无效状态,此时程序若继续使用旧连接执行SQL,会抛出SQLSTATE[HY000]: General error: 2006 MySQL server has gone away异常。处理这一问题的具体做法是在每次查询前增加健康检查。在PHP的PDO扩展中,可以调用$pdo->ping()方法来检测连接是否活跃。如果ping()返回false,或者在执行prepare/execute时捕获到PDOException,则应立即将当前的PDO实例置为null,并触发重新初始化流程。这种重试机制确保了即使底层连接中断,上层业务也能透明地获取到一个新的可用连接,从而维持服务的连续性。










