您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > php

PHP进阶教程-实现一个简单的MySQL连接池

时间:2020-05-29 10:37:55  来源:  作者:

什么是连接池?

顾名思义,连接池就是一堆预先创建好的连接,跟容器会有点像。连接池主要是在某种需要网络连接的服务,提前把连接建立好存起来,然后存放在一个池子里面,需要用到的时候取出来用,用完之后再还回去。

MySQL连接过程

client 建立连接的认证过程

  • 1、server 监听端口
  • 2、client 向server建立TCP连接
  • 3、server 向client发送挑战码报文(报文详细内容在下文中有分析)
  • 4、client 使用挑战码加密密码,将加密后的密码包含在回包中,发送给server
  • 5、server 根据client的回包,验证密码的有效性,给client发送ok包或error包
  • 6、client发送SQL执行
  • 7、关闭MySQL关闭、TCP连接
PHP进阶教程-实现一个简单的MySQL连接池

 

为什么使用连接池?

PHP进阶教程-实现一个简单的MySQL连接池

 

从图可以看到想要执行一条SQL语句每次都要走 图:3.5-1都过程,至少要7步才可以成功。MySQL会有连接数上限的限制,而且每次都执行那么多都步骤,频繁把时间浪费在了网络IO上。

没有连接池的做法类似我们买菜做饭,比如我们要做十个菜,每做一个菜就跑一趟菜市场,挑菜、讨价还价、回家、洗菜、下锅、起锅、洗锅;这样是不是很浪费时间?那我们想要做十个菜,提前把这十个菜的材料都买回来,都洗好备用,然后每次炒都时候直接下锅炒就好了。连接池就是提前买好菜,洗好菜(创建连接、验证账号密码),在要炒菜的时候直接下锅(执行SQL)炒。

PHP进阶教程-实现一个简单的MySQL连接池

 

使用连接池之后,只有在连接池初始化的时候就进行连接然后存到一个容器里面。每次要执行SQL语句的时候先来这个池获取连接对象,然后再发送SQL语句,当SQL语句执行完之后,再把这个连接归还给连接池。

使用连接池每次执行SQL语句只需要执行 图:3.5-1 的第6步就行了,复用了MySQL连接,在高并发情况下,节省了每次连接带来的其他开销。

连接池有什么?

  • 最小连接数
  • 最大连接数
  • 当前连接数
  • 连接池对象
  • 获取连接池超时时间
  • 健康度检查

实战:Swoole实现连接池

MysqlPool.php

/**
 * 1、设置配置信息
 * 2、创建连接对象
 * 3、获取连接对象
 * 4、获取连接对象,空闲连接不够创建到最大连接数
 * 5、执行sql语句
 * 6、归还连接
 */

use SwooleCoroutineChannel;

class MysqlPool
{
    // 最小连接数
    private $min;
    // 最大连接数
    private $max;
    // 当前连接数
    private $count = 0;
    // 获取超时时间
    private $timeOut = 0.2;
    // 连接池对象容器
    private $connections;
    // 配置信息
    private $config = [];
    // 连接池对象
    private static $instance;
    public function __construct(array $config){
        $this->config = $config;
        $this->min = $this->config['min'] ?? 2;
        $this->max = $this->config['max'] ?? 4;
        $this->timeOut = $this->config['time_out'] ?? 0.2;
        $this->connections = new Channel($this->max);
    }

    /**
     * 获取连接池对象
     * @param null $config
     * @return MysqlPool
     */
    public static function getInstance($config = null){
        if (empty(self::$instance)) {
            if (empty($config)) {
                throw new RuntimeException("mysql config empty");
            }
            self::$instance = new static($config);
        }

        return self::$instance;
    }

    /**
     * 初始化连接池
     * @throws Exception
     */
    public function init(){
        for ($i = 0; $i < $this->min; $i++) {
            $this->count++;
            $mysql = $this->createDb();
            $this->connections->push($mysql);
        }

    }

    /**
     * 创建数据库连接对象
     * @return PDO
     * @throws Exception
     */
    private function createDb(){
        $dsn = "mysql:dbname={$this->config['database']};host={$this->config['db_host']}";
        try {
            $mysql = new PDO($dsn, $this->config['db_user'], $this->config['db_passwd']);
            return $mysql;
        } catch (PDOException $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 获取数据库连接
     * @return mixed|null|PDO
     * @throws Exception
     */
    public function getConnection(){
        $mysql = null;
        // 判断是否为空,如果池空了,判断当前连接数是否下于最大连接数
        // 如果小于最大连接数创建新连接数
        if ($this->connections->isEmpty()) {
            if ($this->count < $this->max) {
                $this->count++;
                $mysql = $this->createDb();
            } else {
                $mysql = $this->connections->pop($this->timeOut);
            }
        } else {
            $mysql = $this->connections->pop($this->timeOut);
        }
        // 获取不到数据库连接抛出异常
        if (!$mysql) {
            throw new Exception('没有连接了');
        }
        // 当协程结束之后归还连接池
        defer(function () use ($mysql) {
            $this->connections->push($mysql);
        });
        return $mysql;
    }

    /**
     * 调试打印连接池的容量,非主要代码
     * @param $str
     */
    public function printLenth($str){
        echo $str . $this->connections->length() . "n";
    }
}

server.php

include './MysqlPool.php';
//创建http server
$http = new SwooleHttpServer("0.0.0.0", 9501);
$http->set(["worker_num" => 2]);
$http->on('WorkerStart', function ($serv, $worker_id) {
    $config = [
        'min' => 3,
        'max' => 5,
        'time_out' => 1,
        'db_host' => '127.0.0.1',
        'db_user' => 'root',
        'db_passwd' => 'sunny123',
        'database' => 'lv'
    ];
    MysqlPool::getInstance($config)->init();
});

$http->on('request', function ($request, $response) {
    try {
        MysqlPool::getInstance()->printLenth(SwooleCoroutine::getCid() . '获取前:');
        $mysql = MysqlPool::getInstance()->getConnection();
        MysqlPool::getInstance()->printLenth(SwooleCoroutine::getCid() . '归还前:');
        $result = $mysql->query("select * from sunny_member");
        $row = $result->fetch(MYSQLI_ASSOC);
        MysqlPool::getInstance()->printLenth(SwooleCoroutine::getCid() . '归还后:');
        $response->end($row['content']);
    } catch (Exception $e) {
        $response->end($e->getMessage());
    }
});
$http->start();

本案例实现:

  • 最小连接数
  • 最大连接数
  • 当前连接数
  • 连接池对象
  • 获取连接池超时时间

思考:怎么实现健康度检查?



Tags:MySQL连接池   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
什么是连接池?顾名思义,连接池就是一堆预先创建好的连接,跟容器会有点像。连接池主要是在某种需要网络连接的服务,提前把连接建立好存起来,然后存放在一个池子里面,需要用到的时候...【详细内容】
2020-05-29  Tags: MySQL连接池  点击:(77)  评论:(0)  加入收藏
▌简易百科推荐
序言:前段时间织梦因为版权的问题在网上闹得沸沸扬扬,也提醒了众多开发者选择cms上应该谨慎使用,今天给大家展示一款自己搭建的内容管理系统,不用担心版权的问题,而且非常容易维...【详细内容】
2021-11-30  小程序软件开发    Tags:管理系统   点击:(34)  评论:(0)  加入收藏
准备安装包(PHP: Hypertext Preprocessor)下载安装包以及组件wget https://www.php.net/distributions/php-8.0.0.tar.bz2wget https://github.com/phpredis/phpredis/archive...【详细内容】
2021-11-09  mimic96    Tags:PHP   点击:(40)  评论:(0)  加入收藏
golang context 很好用,就使用php实现了github地址 : https://github.com/qq1060656096/php-go-context context使用闭坑指南1. 将一个Context参数作为第一个参数传递给传入和...【详细内容】
2021-11-05  1060656096    Tags:PHP   点击:(41)  评论:(0)  加入收藏
一段数组为例:$list = array:4 [ 0 => array:7 [ "id" => 56 "mer_id" => 7 "order_id" => "wx163265961408769974" "is_postage" => 0 "store_name" => "奇...【详细内容】
2021-09-29  七七小影视    Tags:PHP   点击:(65)  评论:(0)  加入收藏
利用JS的CryptoJS 3.x和PHP的openssl_encrypt,openssl_decrypt实现AES对称加密解密,由于需要两种语言对同一字符串的操作,而CryptoJS 的默认加密方式为“aes-256-cbc”,PHP端也...【详细内容】
2021-09-16  李老师tome    Tags:对称加密   点击:(79)  评论:(0)  加入收藏
1、checkdate()验证格利高里日期即:日期是否存在。checkdate(month,day,year);month必需。一个从 1 到 12 的数字,规定月。day必需。一个从 1 到 31 的数字,规定日。year必需。...【详细内容】
2021-08-31  七七小影视    Tags:时间函数   点击:(80)  评论:(0)  加入收藏
对于各类开发语言来说,整数都有一个最大的位数,如果超过位数就无法显示或者操作了。其实,这也是一种精度越界之后产生的精度丢失问题。在我们的 PHP 代码中,最大的整数非常大,我...【详细内容】
2021-08-26  硬核项目经理    Tags:PHP   点击:(83)  评论:(0)  加入收藏
遵从所有教材以及各类数据结构相关的书书籍,我们先从线性表开始入门。今天这篇文章更偏概念,是关于有线性表的一个知识点的汇总。上文说过,物理结构是用于确定数据以何种方式存...【详细内容】
2021-07-19  硬核项目经理    Tags:线性表   点击:(94)  评论:(0)  加入收藏
一、开启IIS全部功能。二、部署PHP1.官网下载并解压PHP: https://windows.php.net/downloads/releases/2.将php.ini-development文件改为php.ini3.修改php.ini(1)去掉注释,并修...【详细内容】
2021-07-15  炘蓝火诗  今日头条  Tags:PHP环境   点击:(129)  评论:(0)  加入收藏
一、环境说明本文中使用本地VM虚机部署测试。OS:CentOS Linux release 7.8.2003 (Core)虚机配置:2核CPU、4G内存①系统为CentOS 7.8 x64最小化安装,部署前已完成系统初始化、...【详细内容】
2021-06-25  IT运维笔记  今日头条  Tags:PHP8.0.7   点击:(141)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条