PDO关闭连接


120

与MySQLi相比,关于PDO只是一个相当简单的问题。

使用MySQLi,可以关闭连接:

$this->connection->close();

但是,对于PDO,它指出您使用以下方法打开连接:

$this->connection = new PDO();

但是要关闭连接,请将其设置为null

$this->connection = null;

这是正确的吗,这实际上会释放PDO连接吗?(我知道它的设置是正确的null。)我的意思是,对于MySQLi,您必须调用一个函数(close)来关闭连接。PDO和= null断开一样容易吗?还是有关闭连接的功能?


11
我问的原因是我不确定我是否正确关闭了连接。但不是真的很有趣
Liam Sorsby 2013年

2
当您的PHP脚本停止执行时,数据库连接将自动关闭。
马丁·比恩

3
如果您已完成使用它,那么为什么不继续并终止它,尤其是当您完成与数据库的交互后,如果有一些耗时的代码,则尤其如此。不过,尽管如此,我也没有真正看到等待脚本完成的问题(除了减少与数据库服务器的连接。)
Kieran 2013年


23
并非所有的php脚本都是短暂的。有php守护进程在那里。我个人认为这是一件好事。
datUser 2014年

Answers:


146

根据文档,您是正确的(http://php.net/manual/zh/pdo.connections.php):

该连接在该PDO对象的生存期内保持活动状态。要关闭连接,您需要通过确保删除所有剩余的对该对象的引用来销毁该对象,方法是将NULL分配给保存该对象的变量。如果您未明确执行此操作,则PHP将在脚本结束时自动关闭连接

请注意,如果将PDO对象初始化为持久连接,它将不会自动关闭连接。


4
如果我的流程没有结束怎么办?例如websocket。有没有办法不使用持久连接?
拉斐尔·莫尼

1
对于长时间运行的脚本中的持久连接,您可能有意(或无意中)使连接由于超时(例如,在my.ini中)或其他原因而被终止。连接或运行查询时,请捕获任何错误,如果错误是“ MySQL已经消失”,请尝试再次连接或再次运行查询。
Frank Forte

1
Note that if you initialise the PDO object as a persistent connection it will not automatically close the connection但是,如果连接是持久的,并且我在脚本结束之前显式调用了NULL,那么即使它是持久的,连接也会关闭,对吗?
tonix

1
@tonix不,应将其释放(可用于其他脚本),但不能关闭。
本杰明

2
@tonix我想是的,是的。引用PHP手册中关于持久性连接的说明警告使用持久性连接时,还需要牢记一些其他警告。其中之一是,在持久性连接上使用表锁定时,如果脚本由于某种原因无法释放锁,然后使用相同连接的后续脚本将无限期阻止,并可能需要您重新启动httpd服务器或数据库服务器。”
本杰明

46
$conn=new PDO("mysql:host=$host;dbname=$dbname",$user,$pass);
    // If this is your connection then you have to assign null
    // to your connection variable as follows:
$conn=null;
    // By this way you can close connection in PDO.

11
恕我直言,我认为这是一个非常糟糕的模式,尤其是当开发人员可能存储pdo参考的多个副本时。$ a =新的PDO(...); $ b = $ a; $ a = null; 在那里,您的PDO对象将永远保持打开状态(在类似守护程序的php程序中)。当PDO引用跨函数和对象属性传播时,尤其如此,并且您永远不能确保将所有这些都清空。
加百利

33
在PDO上应该有一个-> close()方法。
加百利

5
不喜欢PDO的另一个原因。
何塞·卡洛斯·PHP

6
@Gabriel-我建议“存储多个副本”是更糟糕的模式。
里克·詹姆斯

4
如果您在这两行之间(即在每种实际情况下)都创建了PDOStatement对象,则此方法不起作用。要关闭连接,必须将PDO对象和PDOStatement对象都设置为null。看到这里:php.net/manual/en/pdo.connections.php#114822
Ilmari

8

它不仅仅是将连接设置为null。那可能是文​​档所说的,但这不是mysql的真相。连接将保持更长的时间(我听说过60秒钟,但从未测试过)

如果要在此处进行完整说明,请参阅以下有关连接的注释https://www.php.net/manual/zh/pdo.connections.php#114822

要强制关闭连接,您必须执行以下操作

$this->connection = new PDO();
$this->connection->query('KILL CONNECTION_ID()');
$this->connection = null;

谢谢您的回答。问题来自很久以前,但是您对连接的权利。
利亚姆·索斯比

我实际上不同意通过PHP处理TCP连接是一个好主意。所有低层TCP连接处理都被抽象掉了,因此我们只需要在运行时处理高层类和对象即可。PHP是一种基于请求的语言(您可能知道),因此终止与dB的潜在持久连接可能会导致用户意外的错误/问题。您链接到的用例很可能会导致驱动程序保持持久性连接处于打开状态,以供其他请求使用,因此我认为这是预期的行为。
利亚姆·索斯比

如果您实际查看mysql中的进程列表,它将显示仍然存在的连接。我同意您不应该这样弄乱TCP连接,并且应该有一种方法可以正确断开连接。但事实并非如此。因此,如果您确实想与服务器断开连接,则必须执行以下操作。将连接设置为null不会断开与文档所说的相反的连接。
Jdahern

我已经找到了以下解释:stackoverflow.com/a/18277327/1315873
Fil

7

我创建了一个派生类,使其具有更多的自我文档说明,而不是“ $ conn = null;”。

class CMyPDO extends PDO {
    public function __construct($dsn, $username = null, $password = null, array $options = null) {
        parent::__construct($dsn, $username, $password, $options);
    }

    static function getNewConnection() {
        $conn=null;
        try {
            $conn = new CMyPDO("mysql:host=$host;dbname=$dbname",$user,$pass);
        }
        catch (PDOException $exc) {
            echo $exc->getMessage();
        }
        return $conn;
    }

    static function closeConnection(&$conn) {
        $conn=null;
    }
}

所以我可以在以下之间调用我的代码:

$conn=CMyPDO::getNewConnection();
// my code
CMyPDO::closeConnection($conn);

1
您可以CMyPDO :: __构造()方法的私人和使用Singleton模式的有..
阿迪亚Hajare

是的,有可能。如果一次使用多个数据库,则还需要通过另一种方法分配连接信息。区别很小,只是您几乎没有更长的指令来调用实例方法。
截至

@AdityaHajare您不能在子类中
将超

@nickdnk,你是对的。我的意思是创建一个独立的类CMyPDO(不使其扩展PDO),然后在CMyPDO的私有构造函数(新PDO($ dsn,$ dbuser,$ dbpass);)类中创建数据库实例。实例在整个应用程序中都可用(Singleton设计模式)。
Aditya Hajare

1
@Fil但是代码“外部” closeConnection应该不知道它需要复制对变量的引用而不是分配对象。换句话说,您尝试编码接近的PDO函数的方式有不良的副作用,使其不可靠。这样做的唯一方法是closeConnection检查代码中存在多少对PDO对象的引用,并在存在1个以上的情况下抛出该异常。
Xenos

-1
<?php if(!class_exists('PDO2')) {
    class PDO2 {
        private static $_instance;
        public static function getInstance() {
            if (!isset(self::$_instance)) {
                try {
                    self::$_instance = new PDO(
                        'mysql:host=***;dbname=***',
                        '***',
                        '***',
                        array(
                            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_general_ci",
                            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION
                        )
                    );
                } catch (PDOException $e) {
                    throw new PDOException($e->getMessage(), (int) $e->getCode());
                }
            }
            return self::$_instance;
        }
        public static function closeInstance() {
            return self::$_instance = null;
        }
    }
}
$req = PDO2::getInstance()->prepare('SELECT * FROM table');
$req->execute();
$count = $req->rowCount();
$results = $req->fetchAll(PDO::FETCH_ASSOC);
$req->closeCursor();
// Do other requests maybe
// And close connection
PDO2::closeInstance();
// print output

使用自定义类PDO2的完整示例。


1
请从您的代码或者删除尝试捕捉或添加新的投内部,如图这里。现在,您的代码通常会同时滥用异常和错误报告
您的常识
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.