在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 的长生命周期服务中使用。

相关推荐
小蒜学长7 小时前
springboot多功能智能手机阅读APP设计与实现(代码+数据库+LW)
java·spring boot·后端·智能手机
追逐时光者8 小时前
精选 4 款开源免费、美观实用的 MAUI UI 组件库,助力轻松构建美观且功能丰富的应用程序!
后端·.net
你的人类朋友8 小时前
【Docker】说说卷挂载与绑定挂载
后端·docker·容器
间彧9 小时前
在高并发场景下,如何平衡QPS和TPS的监控资源消耗?
后端
间彧9 小时前
QPS和TPS的区别,在实际项目中,如何准确测量和监控QPS和TPS?
后端
间彧9 小时前
消息队列(RocketMQ、RabbitMQ、Kafka、ActiveMQ)对比与选型指南
后端·消息队列
brzhang10 小时前
AI Agent 干不好活,不是它笨,告诉你一个残忍的现实,是你给他的工具太难用了
前端·后端·架构
brzhang10 小时前
一文说明白为什么现在 AI Agent 都把重点放在上下文工程(context engineering)上?
前端·后端·架构
Roye_ack11 小时前
【项目实战 Day9】springboot + vue 苍穹外卖系统(用户端订单模块 + 商家端订单管理模块 完结)
java·vue.js·spring boot·后端·mybatis
AAA修煤气灶刘哥12 小时前
面试必问的CAS和ConcurrentHashMap,你搞懂了吗?
后端·面试