完全理解PDO ATTR_PERSISTENT

时间:2014-05-02 16:35:24

标签: php oracle pdo oracle10g

问题:

使用PDO时,持久连接管理背后的规则/逻辑是什么?


环境:

Web服务器

  • Windows 7 x64
  • 具有16GB RAM的双核
  • Apache 2.2.17
  • PHP 5.3.5
  • 通过DSN字符串连接IP地址,端口,服务名称等......
  • DB conn没有ODBC(现在尝试创建一个2小时,感谢Oracle!)

数据库服务器

  • Linux上的Oracle 10g
  • 4GB RAM的多核
  • 专门为我的网络应用创建的用户名(是的,这是假的)
    • user:webuser

我的理解/观察:

非持久性连接

<?php

// Open a new connection
// Session created in Oracle
$dbh = new PDO('DSN', 'webuser', 'password');

// webuser is active in v$session with a SID=1

$dbh = NULL;

// webuser removed from v$session

// Manually calling $dbh = NULL; will remove the session from v$session
// OR
// Wait for script EOL so a kill-session command is sent to Oracle?

?>
  • 脚本可靠地花费大约.09秒来执行框架开销等...

持久连接

<?php

// Open a new connection and make it persistent
// Session created in Oracle
// Is Apache maintaining some sort of keep-alive with Oracle here?
// because I thought php.exe is only alive for the duration of the script
$dbh = new PDO('DSN', 'webuser', 'password', array(PDO::ATTR_PERSISTENT => TRUE));

// webuser is active in v$session with a SID=1

$dbh = NULL;

// webuser is still active in v$session with a SID=1

$dbh = new PDO('DSN', 'webuser', 'password', array(PDO::ATTR_PERSISTENT => TRUE));

// webuser is still active in v$session with a SID=1

// Manually calling $dbh = NULL; does not kill session
// OR
// Script EOL does not kill session
// ^^ this is good, just as expected

?>
  • 脚本在初始访问时需要〜.12秒才能执行框架开销等...
  • 后续执行~0.04

问题:

我访问了该网页,webuser获得了SID=1

我的同事访问该页面,webuser获取额外的SID=2&lt; - 为访问此页面的新计算机进行冲洗,重复和增加SID

新访客是否应该重新使用SID=1


欢迎所有答案,建议,替代测试请求,阅读材料链接。

我有一段时间的RTFM,Googling只制作了微薄的Advantages of Persistent vs. Non-persistent博客。

3 个答案:

答案 0 :(得分:34)

Apaches观点

Apache有一个父进程。此过程创建子进程,以处理进入Web服务器的任何请求。 Web服务器启动时启动的初始子进程数由apache配置中的StartServers指令配置。在需要ServerLimit到达{{1}}之前,会有大量请求到达Web服务器,因此数量会增加。

PHP和持久连接

如果PHP(作为CGI运行,因为CGI所有资源在脚本执行结束时被释放)现在被告知要与数据库建立持久连接请求,即使脚本完成,此连接也会保持。 现在保持的连接是处理请求的apache子进程与数据库服务器之间的连接,并且可以由此精确子进程正在处理的任何请求重用。

如果由于某种原因(不要问我确切原因),子进程占用的时间比实际请求长,而另一个请求进来,则父apache进程将此请求重定向到(新)子进程,到目前为止还没有建立与数据库的连接。如果必须在执行脚本期间,它会像您所观察到的那样提升SID。现在有两个连接由两个不同的apache子进程保持。

请记住......

重要的是要知道,这也会造成很多麻烦。 如果在脚本执行期间存在无限循环或中止事务或某些其他可能甚至是不可预测的错误,则连接被阻止且无法重新使用。 此外,可能会使用数据库的所有可用连接,但是apache服务器的另一个子进程正在尝试访问数据库。 此过程暂时被阻止,直到数据库或apache释放连接(超时或自动终止)。 有关此主题的更多信息,请参见本页:http://www.php.net/manual/en/features.persistent-connections.php

我希望我已经在我们的评论对话中正确总结了我们所讨论的一切,并且没有忘记任何事情。 如果是这样,请给我一个提示,我会添加它。 :)

编辑:

我刚读完this comment中提到的文章@MonkeyZeus。 它描述了我在上面总结的过程,并提供了有关如何优化Apache服务器以便与持久连接一起更好地工作的有用信息。 但是,无论有没有oracle数据库后端,它都可以使用。 你应该看看:http://www.oracle.com/technetwork/articles/coggeshall-persist-084844.html

答案 1 :(得分:2)

优势

php的手册页上了解this link上的持久连接:

  

持久连接是在脚本执行结束时不会关闭的链接。当请求一个持久连接时,PHP检查是否已经存在一个相同的持久连接(从较早版本开始一直保持打开状态)-如果存在,则使用它。如果不存在,则会创建链接。

使用持久连接的原因当然是减少了相当昂贵的连接数量。即使使用MySQL比使用其他大多数数据库要快得多。

问题

使用持久连接时,table locking存在一些问题。

  

如果由于某种原因该脚本无法释放锁定,则使用相同连接的后续脚本将无限期阻塞,并可能需要您重新启动httpd服务器或数据库服务器。

另一个是通过mysql commit使用事务时。

  

如果脚本执行在事务块之前结束,则事务块还将继续使用下一个使用该连接的脚本。无论哪种情况,您都可以使用register_shutdown_function()注册一个简单的清除函数来解锁表或回滚事务。

我建议您阅读this question,了解持久连接的缺点。

答案 2 :(得分:-1)

PDO有点好笑。即使是相同的用户/访问者也可以创建第二个甚至第三个实例。在我的本地机器上发生了同样的事情,同时测试了我的数据库查询的性能。

这没什么可担心的,因为这些实例迟早会超时,确切的超时时间取决于您的服务器配置。

为什么会这样?如果当前实例正忙,则将创建一个新实例,旧实例迟早会超时。至少对我来说这似乎是合乎逻辑的。