详解PHP中的数据库连接持久化

admin3年前PHP教程99
目录
PHP中的数据库连接持久化什么是数据库连接持久化连接持久化有什么用?效率对比注意总结
PHP中的数据库连接持久化

数据库的优化是我们做web开发的重中之重,甚至很多情况下其实我们是在面向数据库编程。当然,用户的一切操作、行为都是以数据的形式保存下来的。在这其中,数据库的连接创建过程有没有什么可以优化的内容呢?答案当然是有的,Java等语言中有连接池的设定,而PHP在普通开发中并没有连接池这种东西,在牵涉到多线程的情况下往往才会使用连接池的技术,所以PHP每次运行都会创建新的连接,那么这种情况下,我们如何来优化数据连接呢?

什么是数据库连接持久化

我们先来看下数据库连接持久化的定义。

持久的数据库连接是指在脚本结束运行时不关闭的连接。当收到一个持久连接的请求时。PHP 将检查是否已经存在一个(前面已经开启的)相同的持久连接。如果存在,将直接使用这个连接;如果不存在,则建立一个新的连接。所谓“相同”的连接是指用相同的用户名和密码到相同主机的连接。

对 web 服务器的工作和分布负载没有完全理解的读者可能会错误地理解持久连接的作用。特别的,持久连接不会在相同的连接上提供建立“用户会话”的能力,也不提供有效建立事务的能力。实际上,从严格意义上来讲,持久连接不会提供任何非持久连接无法提供的特殊功能。

这就是PHP中的连接持久化,不过它也指出了,持久连接不会提供任何非持久连接无法提供的特殊功能。这就很让人疑惑了,不是说好了这个方案可以带来性能的提升吗?

连接持久化有什么用?

没错,从上述定义中指出的特殊功能来看,持久化连接确实没有带来新的或者更高级的功能,但是它最大的用处正是提升了效率,也就是性能会带来提升。

当Web Server创建到SQL服务器的连接耗费(Overhead)较高(如耗时较久,消耗临时内存较多)时,持久连接将更加高效。

也就是说连接耗费高的时候,创建数据库连接的成本开销也会越大,时间当然也越长。使用持久化连接之后,使得每个子进程在其生命周期中只做一次连接操作,而非每次在处理一个页面时都要向SQL 服务器提出连接请求。这也就是说,每个子进程将对服务器建立各自独立的持久连接。

例如,如果有 20 个不同的子进程运行某脚本建立了持久的 SQL 服务器持久连接,那么实际上向该 SQL 服务器建立了 20 个不同的持久连接,每个进程占有一个。

效率对比

话不多说,我们直接通过代码来对比。首先,我们定义好一个统计函数,用来返回当前的毫秒时间。另外,我们还要准备好数据的连接参数。


function getmicrotime()
{
    list($usec, $sec) = explode(" ", microtime());
    return ((float) $usec + (float) $sec);
}
 
$db = [
    'server' => 'localhost:3306',
    'user' => 'root',
    'password' => '',
    'database' => 'blog_test',
];

接下来,我们先使用普通的 mysqli 进行测试。


$startTime = getmicrotime();
for ($i = 0; $i < 1000; $i++) {
    $mysqli = new mysqli($db["server"], $db["user"], $db["password"], $db["database"]); //持久连接
    $mysqli->close();
}
echo bcsub(getmicrotime(), $startTime, 10), PHP_EOL;
// 6.5814000000

在 1000 次的循环创建数据库的连接过程中,我们消耗了6秒多的时间。接下来我们使用持久化连接的方式进行这 1000 次的数据库连接创建。只需要在 mysqli 的 $host 参数前加上一个 p: 即可。


$startTime = getmicrotime();
for ($i = 0; $i < 1000; $i++) {
    $mysqli = new mysqli('p:' . $db["server"], $db["user"], $db["password"], $db["database"]); //持久连接
    $mysqli->close();
}
echo bcsub(getmicrotime(), $startTime, 10), PHP_EOL;
// 0.0965000000

从 mysqli 的连接上来看,效率提升非常明显。当然,PDO 方式的数据库连接也提供了建立持久连接的属性。


$startTime = getmicrotime();
for ($i = 0; $i < 1000; $i++) {
    $pdo = new PDO("mysql:dbname={$db['database']};host={$db['server']}", $db['user'], $db['password']);
}
echo bcsub(getmicrotime(), $startTime, 10), PHP_EOL;
// 6.6171000000
 
$startTime = getmicrotime();
for ($i = 0; $i < 1000; $i++) {
    $pdo = new PDO("mysql:dbname={$db['database']};host={$db['server']}", $db['user'], $db['password'], [PDO::ATTR_PERSISTENT => true]); //持久连接
}
echo bcsub(getmicrotime(), $startTime, 10), PHP_EOL;
// 0.0398000000

PDO 方式连接时,需要给一个 PDO::ATTR_PERSISTENT 参数并设置为 true 。这样就让 PDO 建立的连接也成为了持久化的连接。

注意

既然数据库的持久化连接这么强大,为什么不默认就是这种持久化的连接形式,而需要我们手动增加参数来实现呢?PHP 的开发者们当然还是有顾虑的。

如果持久连接的子进程数目超过了设定的数据库连接数限制,系统将会产生一些问题。如果数据库的同时连接数限制为 16,而在繁忙会话的情况下,有 17 个线程试图连接,那么有一个线程将无法连接。如果这个时候,在脚本中出现了使得连接无法关闭的错误(例如无限循环),则该数据库的 16 个连接将迅速地受到影响。

同时,表锁和事务也有需要注意的地方。

在持久连接中使用数据表锁时,如果脚本不管什么原因无法释放该数据表锁,其随后使用相同连接的脚本将会被持久的阻塞,使得需要重新启动 httpd 服务或者数据库服务

在使用事务处理时,如果脚本在事务阻塞产生前结束,则该阻塞也会影响到使用相同连接的下一个脚本

所以,在使用表锁及事务的情况下,最好还是不要使用持久化的数据库连接。不过好在持久连接和普通连接是可以在任何时候互换的,我们定义两种连接形式,在不同的情况下使用不同的连接即可解决类似的问题。

总结

事物总有两面性,持久连接一方面带来了效率的提升,但另一方面也可能带来一些业务逻辑上的问题,而且这种问题如果在不了解持久连接的机制的情况下会非常难排查。因此,在日常开发中我们一定要在了解相关功能特性的情况下再选择适合的方式来完成所需要的功能开发。

测试代码:

github/zhangyue050…

以上就是详解PHP中的数据库连接持久化的详细内容,更多关于PHP 数据库连接持久化的资料请关注其它相关文章!

免责声明:本文内容来自用户上传并发布,站点仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。请核实广告和内容真实性,谨慎使用。

相关文章

PHP的重载使用魔术方法代码实例详解

摘录PHP官网对PHP重载的解释:PHP所提供的"重载"(overloading)是指动态地"创建"类属性和方法。我们是通过魔术方法(magic methods...

租用国外站群服务器有哪些注意事项呢

在网站优化工作中,站长们常常使用国外站群服务器来作为辅助工具,国外站群服务器具有多IP的优势,帮助站群优化网站的排名引入更多优质流量。那么租用国外站群服务器有哪些注意事项呢?下面小编就给大家说说。一、...

租用法国服务器中国访问速度怎么样

租用法国服务器中国访问速度怎么样?租用法国服务器在中国访问速度可能会受到一些限制和影响,因为法国位于欧洲,距离中国较远,需要经过多个网络节点才能连接到中国。这样的情况可能导致访问速度变慢和延迟增加。租...

10个常见网站安全攻击手段及防御方法?美国高防服务器如何防御网络攻击?

在某种程度上,互联网上的每个网站都容易遭受安全攻击。从人为失误到网络罪犯团伙发起的复杂攻击均在威胁范围之内。网络攻击者最主要的动机是求财。无论你运营的是电子商务项目还是简单的小型商业网站,潜在攻击的风...

PHP中 empty() 和 isset() 的区别介绍

目录二者共同点二者区别1、对于未设置的变量的判断2、对于 "" (空字符串) 的判断3、对于 0 (作为整数的0) 的判断4、对于 0.0 (作为浮点数的0) 的判断5、对于 &q...

php计算汉明距离总和的实例讲解

两个整数的汉明距离指的是这两个数字的二进制数对应位不同的数量。计算一个数组中,任意两个数之间汉明距离的总和。实例输入: 4, 14, 2输出: 6解释:在二进制表示中,4表示为0100,14表示为11...