首先看看数据库永久连接的定义:
永久的数据库连接是指在脚本结束运行时不关闭的连接。当收到一个永久连接的请求时。PHP 将检查是否已经存在一个(前面已经开启的)相同的永久连接。如果存在,将直接使用这个连接;如果不存在,则建立一个新的连接。所谓“相同”的连接是指用相同的用户名和密码到相同主机的连接。
PHP使用永久连接方式操作MySQL是有前提的:就是PHP必须安装为多线程或多进程Web服务器的插件或模块。最常见的形式是把PHP用作多进程Apache服务器的一个模块。对于一个多进程的服务器,其典型特征是有一个父进程和一组子进程协调运行,其中实际生成Web页面的是子进程。每当客户端向父进程提出请求时,该请求会被传递给还没有被其它的客户端请求占用的子进程。这也就是说当相同的客户端第二次向服务端提出请求时,它将有可能被一个不同的子进程来处理。在开启了一个永久连接后,所有不同子进程请求SQL服务的后继页面都能够重新使用这个已经建立的 SQL服务器连接。它使得每个子进程在其生命周期中只做一次连接操作,而非每次在处理一个页面时都要向 SQL 服务器提出连接请求。每个子进程将对服务器建立各自独立的永久连接。PHP本身并没有数据库连接池的概念,但是Apache有进程池的概念, 一个Apache子进程结束后会被放回进程池, 这也就使得用mysql_pconnect打开的的那个mysql连接资源可以不被释放,而是依附在相应的Apache子进程上保存到了进程池中。于是在下一个连接请求时它就可以被复用。一切看起来似乎都很正常,但是在Apache并发访问量大的时候,如果使用mysql_pconnect,会由于之前的Apache子进程占用的MySQL连接没有close, 很快使MySQL达到最大连接数,使得之后的请求可能得不到响应。
——————————————————————————
状况一:
使用 1 部 web server 与 1 部 MySQL server(两者可能同在一部主机上),而 web server 固定只对 MySQL server 上的某一个数据库进行存取动作。
因为每次存取数据库时,都是由 web 那边使用同一账号对 MySQL 上的同一数据库作业,若我们将 MySQL 与 web server 的「同时联机数」都调整为 200,就好像 MySQL 这边一直有 200 位「服务生」,随时等着接待来自 web 的 200 位「顾客」似的。而且「顾客」离开之后,「服务生」也不下场休息,时时都站在门口等着接待下一个「顾客」。
在这种情况下,您只要注意将 MySQL 的「同时联机数」调得比 web server 的高或相等,就会发现使用 mysql_pconnect( ) 是个不错的选择。
状况二:
使用 1 部 web server 与 1 部 MySQL server(两者可能同在一部主机上),而 web server 会对 MySQL server 上的两个数据库进行存取动作。
从 web server 那边提出数据存取需求时,有时是针对第 1 个数据库(DB1),有时则是针对第 2 个数据库(DB2)。若我们也将 MySQL 与 web server 的「同时联机数」都调整为 200,这样一来,就好像 MySQL 这边有 200 位「服务生」,但同时经营两个「吧台」(DB1 与 DB2),而「顾客」可能多达 200 位。
一开始,DB1 这个「吧台」比较热门,MySQL 派了 150 位「服务生」上场接待;同样地,当「顾客」离开之后,这 150 位「服务生」仍守着 DB1 而不下场休息。后来,DB2 那边也热闹起来了,「顾客」越来越多,MySQL 得加派「服务生」上场,有几个能派?答案是 50 个!
为什么「服务生」的人力调配会捉襟见肘?那是因为 web 那边使用了 mysql_pconnect( ) 来建立联机。「服务生」一开始被指定到哪个「吧台」工作,就会持续在那边停留,绝不「转台」。
——————————————————————————
请注意,当使用持续性的联机时,每个已建立的联机只为来自同一部 web server、使用同一组账号,且存取同一数据库的使用者服务。
如此一来,假设每部 web server 的「同时联机数」都是 200,而且同时使用 2 部 web server 会怎么样呢?从 web1 来了 50 个「顾客」,先是到 DB1 走一趟,接着再到 DB2 晃一圈,这样需要多少「服务生」接待他们?100 个(web1->DB1: 50 web1->DB2: 50)!又从 web2 来了 50 个「顾客」,也做了同样的动作(web2->DB1: 50 web2->DB2: 50)。在此之后,还有「服务生」是闲着的吗?后续若从 web1 或 web2 同时涌入多于 50 位「顾客」时,谁来应付他们?
倘若您使用的是像 Apache 这类的 multi-process web server(一个 parent process 协调一组 children processes 运作),某个 children process 建立的「持续联机」,是不能分享给其它 children process 来使用的(「服务生」只对先前接待过的「顾客」服务)。在这样的情况下,将会使得 MySQL 上闲置的 process 越积越多(很多「服务生」站在门口等着「老顾客」上门,而不理会「新顾客」)。
mysql_pconnect( ) 一定是最佳选择吗?我想未必尽然。
——– 两者之间的区别 ————–
mysql_pconnect() 和 mysql_connect() 非常相似,但有两个主要区别。
首先,当连接的时候本函数将先尝试寻找一个在同一个主机上用同样的用户名和密码已经打开的(持久)连接,如果找到,则返回此连接
标识而不打开新连接。
其次,当脚本执行完毕后到 SQL 服务器的连接不会被关闭,此连接将保持打开以备以后使用(mysql_close() 不会关闭由
mysql_pconnect() 建立的连接)。
可选参数 client_flags 自 PHP 4.3.0 版起可用。
此种连接称为”持久的”。
看到这里,写一条代码来测试一下
* pconnect_test.php
*/
$link = mysql_pconnect ( " localhost " , " mysql_user " , " mysql_password " )
or die ( " Could not connect: " . mysql_error ()) ;
print ( " Connected successfully " ) ;
通过刷新网页的方式执行这条代码,发现每执行一次,mysql的进程数就增加一个。在这里我不禁有了疑问。上面说mysql_pconnect这个函
数的使用的时候,不是说”当连接的时候本函数将先尝试寻找一个在同一个主机上用同样的用户名和密码已经打开的(持久)连接,如果找到
,则返回此标识而不打开新连接”么?为什么我每刷新一次页面他就给我打开一个新的连接呢?
考虑到这有可能是PHP的bug,我到PHP的bug列表中找关于和too many connections 有关的条目。
相关的话题主要有三个,分别是
#26117 Persistent connection not reused
#13589 Persistent connections stay open and accumulate
描述比较长,我就不在这里贴,具体的内容你自己去看。重点主要是”当一个进程打开一个mysql的持续连接,只要该进程还存在,这个持续
的连接就不会断开,而且每一个进程会打开一个mysql的持续连接,而不能使用其他进程打开的持续连接”。
本文转自博客园知识天地的博客,原文链接:PHP使用数据库永久连接方式操作MySQL的是与非,如需转载请自行联系原博主。