在swoole中使用mysql连接池

今天为大家说一下mysql连接池。

什么是连接池?

连接池是一种存放多个已建立连接的容器,这些连接可以被重复利用,而不必在每次使用时重新建立。 以 MySQL 连接池为例:池中事先创建了若干 MySQL 连接,当程序需要访问数据库时,直接从池中获取一个可用连接,执行完 CRUD(增删改查)操作后再放回池中。

为什么需要连接池?

在传统 PHP(FPM)模式下,每次请求都会重新与 MySQL 建立连接,用完即释放。 建立连接的过程涉及 TCP 握手、权限认证等步骤,通常需要几十毫秒甚至更多,这对高并发系统来说是性能瓶颈。

在 Swoole 中的优势

Swoole 是基于常驻内存的服务模型,程序启动后会一直运行,可以在内存中维护一个 MySQL 连接池。这样:

  • 连接只需在程序启动时创建一次。
  • 之后所有请求都可以直接复用连接,避免重复建立连接的开销。
  • 配合协程,可以同时复用多个连接,提升并发能力。

使用连接池的好处

  1. 性能提升:减少频繁建立连接的时间消耗。
  2. 资源复用:降低 MySQL 的连接压力。
  3. 更稳定:避免在高并发下频繁连接/断开导致的失败率上升。
  4. 可控性强:可设置最大连接数,防止资源被耗尽。

具体案例

下面结合一个实际案例,介绍我在项目中是如何使用 Swoole 创建 MySQL 连接池的。

首先,我们需要用到 Swoole\Coroutine\Channel 类,它是 协程安全的通信容器,用于在协程之间传递数据。 可以简单理解为一个带容量限制的队列:当 push 或 pop 操作无法立即完成时,当前协程会挂起,调度器会去执行其他协程,从而避免阻塞整个进程。

php 复制代码
$this->pool = new Channel(10);

此时 是一个空的队列、有固定容量的协程安全队列,当前元素个数为 0,容量为 10,等待读的协程队列为空,等待写的协程队列为空

接下来,我们使用 \Swoole\Coroutine\MySQL() 创建 MySQL 连接,并将它们推入连接池:

php 复制代码
for ($i = 0; $i < $size; $i++) {
    $mysql = new \Swoole\Coroutine\MySQL();
       $res = $mysql->connect([
           'host' => $config['host'],
           'port' => $config['port'],
           'user' => $config['username'],
           'password' => $config['password'],
           'database' => $config['database'],
           'charset' => $config['charset'] ?? 'utf8mb4',
       ]);
       if (!$res) {
           throw new Exception("MySQL 连接失败: " . $mysql->connect_error);
       }
       $this->pool->push($mysql);
   }

这样,一个简单的 MySQL 连接池就创建完成了(实际应用中可以将其封装成一个类)。 这里需要说明,\Swoole\Coroutine\MySQL() 本身也是协程化的 MySQL 客户端,这保证了在遇到阻塞 I/O 操作时,Swoole 可以切换到其他协程继续执行,从而提升并发性能。

使用连接时,只需从池中 pop() 一个连接,使用完后再 push() 回池中即可。

当 Swoole 服务关闭时,需要清理连接池资源,例如:

php 复制代码
while (true){
     $conn = $this->pool->pop(0.001);
     if($conn === false) break;
     $conn->close();
 }
 $this->pool->close();
 $this->pool = null;

执行逻辑说明:

pop(0.001) 表示等待最多 1 毫秒 获取连接。如果在超时时间内没有数据,会返回 false。 这样可以避免 pop() 长时间挂起。

如果取到了连接,则调用 $conn->close() 关闭连接。

当队列为空或已关闭时,pop() 会返回 false,触发 break 跳出循环。

最后调用 <math xmlns="http://www.w3.org/1998/Math/MathML"> t h i s − > p o o l − > c l o s e ( ) 关闭队列,并将 this->pool->close() 关闭队列,并将 </math>this−>pool−>close()关闭队列,并将this->pool 置为 null。 这样可以断开 PHP 对 Channel 对象的引用,让垃圾回收器(GC)及时销毁它,避免内存泄漏。

这种做法可以确保连接池在使用完毕后被完整、及时地释放,适合在 Swoole 的长生命周期服务中使用。

相关推荐
小兔兔吃萝卜1 小时前
Spring 创建 Bean 的 8 种主要方式
java·后端·spring
Java中文社群1 小时前
26届双非上岸记!快手之战~
java·后端·面试
whitepure2 小时前
万字详解Java中的面向对象(一)——设计原则
java·后端
autumnTop2 小时前
为什么访问不了同事的服务器或者ping不通地址了?
前端·后端·程序员
用户6757049885022 小时前
SQL 判断是否“存在”?99% 的人还在写错!
后端
PetterHillWater2 小时前
12 MCP Servers的介绍
后端·aigc·mcp
杨杨杨大侠2 小时前
02 - 核心模型设计 🧩
后端
小Q圈圈2 小时前
BeanUtils 你走好!MapStruct 才是对象转换的真香神器!
后端