PHP mySQL - 什么时候断开数据库连接最好?

18
我使用“惰性连接”来连接我的数据库。这基本上意味着它在第一次查询之前不会调用mysql_connect(),并且此后跳过重新连接。现在我在我的DB类中有一个名为disconnectFromDB()的方法,它基本上调用mysql_close()并设置$ _connected = FALSE(因此query()方法将知道再次连接到数据库)。这是否应该在每个查询之后被调用(作为私有函数)或通过对象外部调用......因为我在思考类似于以下内容的东西(代码仅为示例)
$students = $db->query('SELECT id FROM students');

$teachers = $db->query('SELECT id FROM teachers');

现在,如果它在每次查询后都关闭,相比于我只添加这行代码到结尾,会减慢速度吗?
$db->disconnectFromDB();

那我是不是应该将上述行放在页面最后呢?

两种方法有什么优缺点?在你的情况下哪个效果最好?忘记关闭mySQL连接除了性能稍微损失一些,还有什么问题吗?

感谢您抽出时间回答。

谢谢!


希望你的应用程序的分区比你的示例所暗示的要好。如果它被封装起来,将更容易跟踪你的懒惰连接。 - dkretz
6个回答

24
据我所知,除非您使用持久连接,否则您的MySQL连接将在页面执行结束时关闭。
因此,您调用断开连接将不会有任何作用,并且由于使用了惰性连接,如果您或其他开发人员在错误的时间断开连接,则可能导致第二个连接被创建。
考虑到这一点,我只需允许连接自动关闭即可。您的页面应该执行得很快,因此保持连接那么短的时间不应该会引起任何问题。

4
+1 表示赞同让 PHP 清理连接(我不建议使用持久连接)。 - Bill Karwin
我也不建议使用持久连接。它们曾经给我带来了无尽的麻烦和难以追踪的错误。 - Rob Prouse
3
我建议您将MySQL中的wait_timeout设置降低。默认值为8小时。大多数网页不需要那么长时间来加载。 - staticsan
9
他们中的大多数都不需要8个小时来加载 :P - pablasso

5

我刚刚在PHP网站上读到了一个关于持久连接的评论,可能会很有趣:

以下是不使用持久连接的重要原因回顾:
1. 当你锁定一个表时,通常在连接关闭时会解锁,但由于持久连接不关闭,任何你意外留下锁定的表都将保持锁定状态,唯一解锁它们的方法是等待连接超时或杀死进程。事务也存在同样的锁定问题。(请参见下面关于2002年4月23日和2003年7月12日的评论)
2. 通常情况下,临时表在连接关闭时会被删除,但由于持久连接不关闭,临时表就不那么临时了。如果你没有明确地在完成后删除临时表,那么这个表将已经存在于重用相同连接的新客户端中。设置会话变量时也存在同样的问题。(请参见下面关于2004年11月19日和2006年8月7日的评论)
3. 如果 PHP 和 MySQL 在同一台服务器或本地网络上,则连接时间可能可以忽略不计,在这种情况下,持久连接没有优势。
4. Apache 不适合使用持久连接。当它从新客户端接收到请求时,它会生成一个新的子进程,而不是使用已经打开持久连接的可用子进程之一。这会导致过多的进程处于睡眠状态,浪费资源,并在达到最大连接时导致错误,同时也破坏了持久连接的任何好处。(请参见下面关于2004年2月3日的评论和http://devzone.zend.com/node/view/id/686#fn1的脚注)

(我不是上面文字的作者)


6
那是从哪里来的?未经引用就从别处复制,是不恰当的行为。 - nobody
里面有建立在非常过时的mysql版本上的信息。我会持怀疑态度来看待它。还有关于PHP的问题。 - dkretz
除了临时表之外,不要忘记MySQL用户变量、会话设置(如CHARSET)和LAST_INSERT_ID()。这些都是针对连接范围的,因此下一个获取该持久连接的Web请求可能会“看到”另一个用户的DB会话状态! - Bill Karwin
这是一篇关于MyISAM行为的PHP手册注释,其中混杂了五年前用户的评论。我建议查找更接近信息源头的更新信息。 - dkretz
前两句话对我来说是“如果你编写的代码不规范,持久连接可能会成为一个问题”。在我看来,这意味着正确的解决方案是“不要编写不规范的代码”,而不是“不要使用持久连接”。 - Dave Sherohman
显示剩余2条评论

5
不需要手动断开连接。每次查询之前检查$_connected变量的成本,加上实际调用$db->disconnectFromDB();进行关闭的成本,最终会比让PHP在页面完成后自动关闭连接更昂贵。
原因如下: 1.如果将连接保持到脚本结束: - PHP引擎循环内部的mysql连接数组。 - PHP引擎为每个连接内部调用mysql_close()。 2.如果你手动关闭连接: - 你必须检查每个查询的$_connected变量值。这意味着PHP必须检查变量$_connected A)是否存在,B)是否是布尔类型,C)是否为true/false。 - 你必须调用你的“断开”函数,而函数调用是PHP中比较昂贵的操作之一。PHP必须检查你的函数A)是否存在,B)是否不是私有/受保护的,C)你是否提供了足够的参数给函数。它还必须在新的局部作用域中创建$connection变量的副本。 - 然后你的“断开”函数会调用mysql_close(),这意味着PHP A)检查mysql_close()是否存在、B)你是否提供了所有所需的参数给mysql_close(),C)它们是否是正确的类型(mysql资源)。
或许我并不是100%正确,但我相信我的说法是正确的。

高度推测性的断言。 - dkretz
是的。PHP 也需要进行相同的检查和调用,而您暴露了系统与开放连接限制的时间比实际需要的要长。 (从美学角度来看,这很懒散,但这是另一个问题。) - dkretz
你有什么建议,doofledorfer...放弃断开连接,但保留懒惰的连接器?这是我目前所做的。 - alex
我认为你没问题。我不同意这个答案所使用的逻辑。虽然答案是正确的,但推理不可靠(也不特别可信)。 - dkretz

2

http://www.mysqlperformanceblog.com/2006/11/12/are-php-persistent-connections-evil/ - Bill Karwin

1

执行的基本单位可能是整个脚本。你首先想要高效有效地应用资源(即数据库)的是单个脚本的整体。

然而,PHP、Apache/IIS/等等,有它们自己的生命周期;并且它们能够在脚本结束后继续使用你打开的连接。这就是持久化(或池化)连接的重要性所在。

回到你的脚本。事实证明,在其执行过程中,你有很大的机会创造性地利用那个连接。

典型的原始脚本倾向于一遍又一遍地访问连接,获取与给定对象/模块/选择选项相关的本地适当数据片段。这就是过程式方法对那个连接施加惩罚的地方,因为需要打开、请求、接收和关闭连接。(请注意,任何一个单独的查询在显式关闭它或者脚本结束之前都将保持活动状态。请注意,连接和查询根本不是同一件事情。查询占用表格;连接占用…连接(在大多数情况下被映射到套接字上)。因此,在使用两者时应该意识到适当的经济性。

与查询相关的最经济的策略是尽可能少地进行查询。我通常会尝试构建一个比较复杂的联合查询,将完整的数据集返回,而不是将请求拆分成小块。

1

使用惰性连接可能是个好主意,因为在某些脚本执行中你可能根本不需要数据库连接。

另一方面,一旦它打开了,就让它保持打开状态,要么在脚本结束时显式地关闭它,要么允许 PHP 清理连接 - 保持打开连接不会对任何事情造成伤害,并且如果你第二次查询数据库,你不想承担检查和重新建立连接的不必要开销。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接