C实现PHP的mysql数据库连接池

48 篇文章 0 订阅

一、导语

连接池在JAVA中应用的很广泛,而在PHP中很少使用。
以Mysql为例,JAVA中使用连接池的原因之一是避免重复新建、释放连接资源带来的开销。而在PHP中都是直连,因为这部分开销对于C API而言性能上是没有问题的。
那么既然PHP直连已经没有性能问题,那为何还要多次一举开发mysql的数据库连接池扩展呢?因为根本的目的是在于理解PHP的TS(Tthread Safe线程安全)与NTS(Not Thread Safe非线程安全)运行模式,而并非数据库连接池这个功能。

二、原理

连接池的基本思想是在系统加载时,初始化默认数量的连接对象存储在内存中,当有客户端需要访问数据库时,根据场景选择是分配、新建、等待、失败返回连接对象。使用完毕之后,连接将被重新放置回连接池中等待下一个请求的再分配,而不是释放内存。
连接池中连接的建立、释放都由连接池自身来管理,同时可以通过设置初始化最小连接数、最大连接数、最大空闲时间等来配置连接池。
注:在此扩展中,提供了最小连接数(min_connection)、最大连接数(max_connection)的设置


三、实现思路

1.定义全局数组变量dbpools
dbpools中的元素类型为
struct _mysql_node{
     MYSQL *mysql;//连接资源句柄
     int is_used;//标记是否被占用
     int result_id;//记录my_mysql_query的查询结果集
} mysql_node;
2.通过获取配置文件中设置的min_connection初始化dbpools
3.定义全局变量db_pools_length(目前拥有链接数)、db_pools_use_length(目前被使用的链接数),通过这两个值来确定分配资源的情景
注:正因为使用全局变量实现连接池,通过修改全局变量的状态来选择资源连接,决定了该扩展必须运行在共享全局变量的ZTS(Zend Thread Safe)线程安全模式下。(例如IIS或Apache MPM Worker模式)
如果希望支持多进程,可以通过进程间通信来设置全局变量,实现线程池。

实现思路图:


四、理解PHP线程与进程的工作模式

(一)多进程工作模式
PHP的多进程工作模式以Apache  apxs举例。
apache启动时,会fork出N个子进程用来等待接受处理客户端的请求。进程之间相互隔离,全局变量也无法直接访问(可以通过进程间通信访问)。这样的好处是能够保证PHP环境的长时间稳定,
即使有部分进程因内存泄漏而崩溃也不会影响其他进程。由于PHP相当于粘合剂,它实际相当于集合多个库的API,例如集合了libcurl、libmemcache、libzip等,要保证所有的库都正常运行是比较困难的。
那么为了保证PHP的高可靠性, 这种多进程的模式就是首选。



(二)多线程工作模式
PHP的多线程工作模式以IIS 举例。
这种模式下,只有一个进程在后台运行着,所有请求都是通过这一个进程来完成。只是在处理每个请求时,会创建独立的线程来处理。
正是因为使用多线程这种模式,可以直接访问全局变量得以方便的实现数据库连接池。


六、使用此扩展前提条件与方法

1.widnwos下IIS Server或Apache多线程模式,php5.3.*
2.修改php.ini,添加
[my_mysql]
my_mysql.host = localhost
my_mysql.user = root
my_mysql.password = 
my_mysql.port = 3306
my_mysql.max_connection = 200 //最大连接数
my_mysql.min_connection = 100  //默认最小连接数
看到这里的配置,能看出来这个数据库连接池扩展没有实现多数据源的连接池。因为目的不在连接池本身,所以也没有特地去写多数据源的功能。
3.修改php.ini,添加
extension=php_my_mysql.dll
4.重启apache server

七、相关下载
扩展dll下载: php_my_mysql.dll

扩展测试结果

测试配置:
[my_mysql]
my_mysql.max_connection = 2 //最大连接数
my_mysql.min_connection = 1  //默认最小连接数
使用三个浏览器,运行下列测试脚本:

<?php
/**
* 从数据库连接池中取得一个链接资源
* 可能产生如下情景
* 1.如果有空闲连接则直接返回链接资源
* 2.如果没有空闲连接,并且连接数没有超过最大连接数,则扩充连接池并返回新建的链接资源
* 3.如果没有空闲连接同时已经是最大连接数,则进入等待,超过1.5s仍没有空闲资源则超时返回NULL.
*
* 失败返回NULL
*/
$db = my_mysql_get_conn();

if($db === false){
     exit('dbpool is exhushed.');
}

/**
* 选择数据库
* @param resource $db
* @param string $db_name 数据库名称
*/
my_mysql_select_db($db, 'test');

/**
* ping数据库
*/
my_mysql_ping($db);

/**
* 执行SQL语句,可以执行INSERT、SHOW、SELECT、UPDATE、DELETE等语句
* @param  resource $db
* @param string $sql SQL
*/
my_mysql_query($db, "INSERT INTO test VALUES(id, 'dbpool', 'test dbpool')");

// //获取上一条INSERT语句返回的自增ID
$id = my_mysql_get_insert_id($db);
echo $id;

$result = my_mysql_query($db, "SELECT * FROM test");

/**
* 将查询结果转换为二维数组
* @param resource $db
*/
$arr = my_mysql_fetch_assoc($result);

print_r($arr);

sleep(3);

var_dump($db);//sleep之后,必须输出$db,否则会因为PHP的解析优化,sleep过程中已经将$db释放,就没有办法测试连接被占用的情况。

测试结果图:

返回warning的,是由于连接池资源被占用完,会进入等待。如果1.5s仍没有等待到资源,则返回dbpool is exhushed。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
PHP中的数据库连接池是一种管理和复用数据库连接的技术,它可以提高数据库操作的性能和效率。通常,每次执行数据库操作时,都需要建立一个新的数据库连接,这会消耗较多的时间和系统资源。而连接池则可以在应用程序启动时预先建立一定数量的数据库连接,并将这些连接保存在连接池中,供后续的数据库操作使用。 以下是一个简单的PHP数据库连接池的示例代码: ```php class ConnectionPool { private $connections = []; private $maxConnections = 10; public function __construct() { // 初始化连接池,创建一定数量的数据库连接 for ($i = 0; $i < $this->maxConnections; $i++) { $connection = $this->createConnection(); $this->connections[] = $connection; } } public function getConnection() { // 从连接池中获取一个可用的数据库连接 if (!empty($this->connections)) { return array_pop($this->connections); } // 连接池中没有可用连接时,创建一个新的连接 return $this->createConnection(); } public function releaseConnection($connection) { // 释放数据库连接,放回连接池中 if (count($this->connections) < $this->maxConnections) { $this->connections[] = $connection; } else { // 连接池已满时,关闭连接 $connection->close(); } } private function createConnection() { // 创建一个新的数据库连接 $connection = new PDO('mysql:host=localhost;dbname=mydatabase', 'username', 'password'); return $connection; } } ``` 使用连接池的示例代码: ```php // 创建连接池对象 $connectionPool = new ConnectionPool(); // 获取数据库连接 $connection = $connectionPool->getConnection(); // 执行数据库操作 // ... // 释放数据库连接,放回连接池中 $connectionPool->releaseConnection($connection); ``` 通过使用连接池,可以减少每次数据库操作时建立和关闭连接的开销,提高性能和效率。同时,连接池也可以控制最大连接数,避免过多的连接导致资源消耗过大。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值