Kết nối đóng PDO


120

Chỉ là một câu hỏi khá đơn giản liên quan đến PDO so với MySQLi.

Với MySQLi, để đóng kết nối, bạn có thể làm:

$this->connection->close();

Tuy nhiên với PDO, nó nói rằng bạn mở kết nối bằng cách sử dụng:

$this->connection = new PDO();

nhưng để đóng kết nối bạn đã đặt nó null.

$this->connection = null;

Điều này có chính xác không và điều này có thực sự giải phóng kết nối PDO không? (Tôi biết nó hoạt động như nó được đặt thành null.) Ý tôi là với MySQLi, bạn phải gọi một hàm ( close) để đóng kết nối. PDO có dễ = nullngắt kết nối không? Hay có chức năng đóng kết nối?


11
lý do tôi hỏi là tôi không chắc liệu tôi đã đóng kết nối đúng cách hay chưa. nhưng không có không thực sự chỉ là hấp dẫn
Liam Sorsby

2
Kết nối cơ sở dữ liệu tự động đóng khi tập lệnh PHP của bạn ngừng thực thi.
Martin Bean

3
Nếu bạn đã sử dụng xong thì tại sao không tiếp tục và chấm dứt nó, đặc biệt là nếu có một số đoạn mã tốn thời gian sau khi bạn hoàn thành tương tác với cơ sở dữ liệu. Mặc dù, tôi không thực sự nhìn thấy vấn đề với chờ đợi kịch bản để kết thúc hoặc là mặc dù (trừ giảm các kết nối đến máy chủ DB.)
Kieran

3
github.com/php/php-src/blob/master/ext/pdo/pdo_dbh.c Tìm hiểu cho chính mình như thế nào nó hoạt động: P
Flosculus

23
Không phải tất cả các tập lệnh php đều tồn tại trong thời gian ngắn. Có daemon php ra khỏi đó. Tôi nghĩ rằng đây là một điều tuyệt vời để làm rõ cá nhân.
datUser

Câu trả lời:


146

Theo tài liệu bạn chính xác ( http://php.net/manual/en/pdo.connections.php ):

Kết nối vẫn hoạt động trong suốt thời gian tồn tại của đối tượng PDO đó . Để đóng kết nối, bạn cần phải hủy đối tượng bằng cách đảm bảo rằng tất cả các tham chiếu còn lại đến nó đều bị xóa - bạn thực hiện việc này bằng cách gán NULL cho biến chứa đối tượng. Nếu bạn không làm điều này một cách rõ ràng, PHP sẽ tự động đóng kết nối khi tập lệnh của bạn kết thúc .

Lưu ý rằng nếu bạn khởi tạo đối tượng PDO dưới dạng kết nối liên tục, nó sẽ không tự động đóng kết nối.


4
Điều gì sẽ xảy ra nếu tôi có một quá trình không kết thúc? ví dụ: websocket. Có cách nào để không sử dụng kết nối liên tục?
Rafael Moni

1
Đối với các kết nối liên tục trong một tập lệnh chạy trong một thời gian dài, bạn có thể cố ý (hoặc vô tình) kết nối bị ngắt do hết thời gian chờ (ví dụ: trong my.ini) hoặc vì một số lý do khác. Khi kết nối hoặc chạy truy vấn, gặp bất kỳ lỗi nào và nếu đó là "MySQL đã biến mất", hãy thử kết nối lại hoặc chạy truy vấn lần thứ hai.
Frank Forte

1
Note that if you initialise the PDO object as a persistent connection it will not automatically close the connectionNhưng nếu một kết nối là liên tục và tôi gọi NULL trên nó một cách rõ ràng trước khi tập lệnh kết thúc, nó sẽ bị đóng ngay cả khi nó liên tục, đúng không?
tonix

1
@tonix Không, nó sẽ được phát hành (có sẵn cho tập lệnh khác), nhưng không bị đóng.
Benjamin

2
@tonix Tôi nghĩ vậy, vâng. Trích dẫn từ hướng dẫn sử dụng PHP về kết nối liên tục : " Cảnh báo Có một số lưu ý bổ sung cần lưu ý khi sử dụng kết nối liên tục. Một là khi sử dụng khóa bảng trên một kết nối liên tục, nếu tập lệnh vì bất kỳ lý do gì không thể giải phóng khóa, thì các tập lệnh tiếp theo sử dụng cùng một kết nối sẽ chặn vô thời hạn và có thể yêu cầu bạn khởi động lại máy chủ httpd hoặc máy chủ cơ sở dữ liệu. "
Benjamin

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
IMHO Tôi nghĩ đó là một mô hình rất tệ, đặc biệt là khi một nhà phát triển có thể lưu trữ một số bản sao của tham chiếu pdo. $ a = new PDO (...); $ b = $ a; $ a = null; Ở đó, đối tượng PDO của bạn sẽ vẫn mở mãi mãi (trong một chương trình php giống daemon). Điều này đặc biệt đúng khi tham chiếu PDO đi qua các hàm và thuộc tính đối tượng, và bạn không bao giờ chắc chắn loại bỏ tất cả chúng.
Gabriel

33
Nên có một phương thức -> close () trên PDO.
Gabriel

5
Một lý do khác để không thích PDO.
José Carlos PHP

6
@Gabriel - Tôi đề nghị rằng "lưu trữ nhiều bản sao" là một mô hình thậm chí còn tồi tệ hơn.
Rick James

4
Điều này không hoạt động nếu bạn đã tạo một đối tượng PDOStatement giữa hai hàng đó (nghĩa là trong mọi tình huống thực tế). Để đóng kết nối, bạn phải đặt cả đối tượng PDO VÀ đối tượng PDOStatement thành null. Xem tại đây: php.net/manual/en/pdo.connections.php#114822
Ilmari

8

Nó không chỉ là đặt kết nối thành null. Đó có thể là những gì tài liệu nói, nhưng đó không phải là sự thật đối với mysql. Kết nối sẽ tồn tại lâu hơn một chút (Tôi đã nghe những năm 60, nhưng chưa bao giờ thử nghiệm nó)

Nếu bạn muốn giải thích đầy đủ ở đây, hãy xem bình luận này trên các kết nối https://www.php.net/manual/en/pdo.connections.php#114822

Để buộc đóng kết nối, bạn phải làm điều gì đó như

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

Cảm ơn bạn vì câu trả lời. Câu hỏi đã có từ khá lâu trước đây nhưng quyền của bạn về kết nối.
Liam Sorsby

Tôi không thực sự đồng ý rằng việc gây rối với Kết nối TCP qua PHP là một ý kiến ​​hay. Tất cả các xử lý kết nối TCP cấp thấp đều được trừu tượng hóa để chúng ta chỉ phải xử lý các đối tượng và lớp cấp cao trong thời gian chạy. PHP là một ngôn ngữ dựa trên yêu cầu (như bạn có thể biết) vì vậy việc hủy kết nối liên tục tiềm ẩn tới dB có thể sẽ dẫn đến các lỗi / sự cố không mong muốn cho người dùng. Trường hợp sử dụng mà bạn liên kết đến có khả năng dẫn đến việc trình điều khiển giữ kết nối liên tục mở để được sử dụng bởi một yêu cầu khác, vì vậy tôi đã nghĩ rằng đây sẽ là hành vi được mong đợi.
Liam Sorsby

Nếu bạn thực sự nhìn vào danh sách quy trình trong mysql, nó sẽ hiển thị kết nối vẫn còn ở đó. Tôi đồng ý rằng bạn không nên làm rối loạn kết nối TCP như thế này và nên có cách ngắt kết nối khỏi kết nối đúng cách. Nhưng đó không phải là trường hợp. Vì vậy, nếu bạn thực sự muốn ngắt kết nối khỏi máy chủ, bạn sẽ phải làm điều gì đó như thế này. Đặt kết nối thành null không ngắt kết nối trái ngược với những gì tài liệu nói.
Jdahern

Tôi đã tìm thấy lời giải thích này: stackoverflow.com/a/18277327/1315873
Fil

7

Tôi đã tạo một lớp dẫn xuất để có một hướng dẫn tự lập tài liệu hơn thay vì "$ 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;
    }
}

Vì vậy, tôi có thể gọi mã của mình giữa:

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

1
Bạn có thể làm CMyPDO :: __ construct () phương pháp riêng và sử dụng singleton pattern có ..
Aditya Hajare

Vâng, nó có thể di động. Bạn cũng cần gán thông tin kết nối bằng một phương pháp khác nếu bạn sử dụng nhiều cơ sở dữ liệu cùng một lúc. Sự khác biệt là tối thiểu, chỉ cần bạn có hướng dẫn dài hơn một chút để gọi các phương thức cá thể.
Fil

@AdityaHajare Bạn không thể thực hiện một phương pháp công cộng của một lớp cha tin trong một lớp con ..
nickdnk

@nickdnk, bạn nói đúng. Ý tôi là tạo một lớp CMyPDO độc lập (không làm cho nó mở rộng PDO) và sau đó tạo một phiên bản cơ sở dữ liệu bên trong một phương thức khởi tạo riêng của CMyPDO (lớp PDO mới ($ dsn, $ dbuser, $ dbpass);) đảm bảo chỉ một lớp thể hiện có sẵn trong toàn bộ ứng dụng (Mẫu thiết kế Singleton).
Aditya Hajare

1
@Fil Nhưng mã "bên ngoài" closeConnectionkhông nên lưu ý rằng nó cần sao chép tham chiếu đến biến thay vì gán đối tượng. Nói cách khác, cách bạn thử mã hóa một hàm PDO đóng có tác dụng phụ xấu, khiến nó không đáng tin cậy. Cách duy nhất để làm như vậy là closeConnectionkiểm tra xem có bao nhiêu tham chiếu đến đối tượng PDO tồn tại trong mã và ném trong trường hợp tồn tại nhiều hơn 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

Ví dụ đầy đủ, với lớp tùy chỉnh PDO2.


1
Vui lòng xóa thử bắt khỏi mã của bạn hoặc thêm một ném mới bên trong như được hiển thị ở đây . Ngay bây giờ mã của bạn lạm dụng cả ngoại lệ và báo cáo lỗi nói chung
Your Common Sense
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.