Koneksi penutupan PDO

121

Hanya pertanyaan yang agak sederhana berkaitan dengan PDO dibandingkan dengan MySQLi.

Dengan MySQLi, untuk menutup koneksi Anda dapat melakukan:

$this->connection->close();

Namun dengan PDO itu menyatakan Anda membuka koneksi menggunakan:

$this->connection = new PDO();

tetapi untuk menutup koneksi yang Anda atur null.

$this->connection = null;

Apakah ini benar dan apakah ini benar-benar membebaskan koneksi PDO? (Saya tahu itu nullberfungsi seperti yang diatur .) Maksud saya dengan MySQLi Anda harus memanggil fungsi ( close) untuk menutup koneksi. Apakah PDO semudah = nullmemutuskan sambungan? Ataukah ada fungsi untuk menutup koneksi?

Liam Sorsby
sumber
11
alasan saya bertanya adalah saya tidak yakin apakah saya menutup koneksi dengan benar. tetapi tidak, tidak benar-benar hanya tertarik
Liam Sorsby
2
Koneksi database secara otomatis ditutup ketika skrip PHP Anda menghentikan eksekusi.
Martin Bean
3
Jika Anda sudah selesai menggunakannya, mengapa tidak melanjutkan dan menghentikannya, terutama jika ada kode yang memakan waktu setelah Anda selesai berinteraksi dengan database. Padahal, saya tidak benar-benar melihat masalah dengan menunggu skrip selesai juga (selain mengurangi koneksi ke server DB.)
Kieran
3
github.com/php/php-src/blob/master/ext/pdo/pdo_dbh.c Cari tahu sendiri cara kerjanya: P
Flosculus
23
Tidak semua skrip php berumur pendek. Ada daemon php di luar sana. Saya pikir ini adalah hal yang bagus untuk diklarifikasi secara pribadi.
datUser

Jawaban:

146

Menurut dokumentasi Anda benar ( http://php.net/manual/en/pdo.connections.php ):

Sambungan tetap aktif selama masa pakai objek PDO tersebut . Untuk menutup koneksi, Anda perlu menghancurkan objek dengan memastikan bahwa semua referensi yang tersisa dihapus - Anda melakukan ini dengan menetapkan NULL ke variabel yang menyimpan objek. Jika Anda tidak melakukan ini secara eksplisit, PHP secara otomatis akan menutup koneksi saat skrip Anda berakhir .

Perhatikan bahwa jika Anda menginisialisasi objek PDO sebagai koneksi persisten, itu tidak akan secara otomatis menutup koneksi.

Kieran
sumber
4
Bagaimana jika saya memiliki proses yang tidak berakhir? misalnya websocket. Apakah ada cara untuk tidak menggunakan koneksi persisten?
Rafael Moni
1
Untuk koneksi persisten dalam skrip yang berjalan untuk waktu yang lama, Anda dapat dengan sengaja (atau tidak sengaja) mematikan koneksi dengan waktu tunggu (misalnya di my.ini), atau karena sejumlah alasan lain. Saat menghubungkan atau menjalankan kueri, tangkap kesalahan apa pun, dan jika "MySQL telah hilang", coba sambungkan lagi atau jalankan kueri untuk kedua kalinya.
Frank Forte
1
Note that if you initialise the PDO object as a persistent connection it will not automatically close the connectionTetapi jika koneksi tetap ada dan saya secara eksplisit memanggil NULL di atasnya sebelum skrip berakhir, itu akan ditutup bahkan jika itu persisten, benar?
tonix
1
@tonix Tidak, itu harus dirilis (tersedia untuk skrip lain), tetapi tidak ditutup.
Benjamin
2
@tonix Saya rasa begitu, ya. Kutipan dari manual PHP tentang koneksi persisten : " Peringatan Ada beberapa peringatan tambahan yang perlu diingat saat menggunakan koneksi persisten. Salah satunya adalah saat menggunakan penguncian tabel pada koneksi persisten, jika skrip karena alasan apa pun tidak dapat melepaskan kunci, maka skrip berikutnya yang menggunakan koneksi yang sama akan memblokir tanpa batas dan mungkin mengharuskan Anda memulai ulang server httpd atau server database. "
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.
himanshu dholakia
sumber
11
IMHO Saya pikir itu adalah pola yang sangat buruk, terutama ketika pengembang mungkin menyimpan beberapa salinan referensi pdo. $ a = PDO baru (...); $ b = $ a; $ a = nol; Di sana, objek PDO Anda akan tetap terbuka selamanya (dalam program php mirip daemon). Ini terutama benar ketika referensi PDO berjalan melintasi fungsi dan properti objek, dan Anda tidak pernah yakin untuk membatalkan semuanya.
Gabriel
33
Harus ada metode -> close () pada PDO.
Gabriel
5
Alasan lain untuk tidak menyukai PDO.
José Carlos PHP
6
@ Gabriel - Saya menyarankan bahwa "menyimpan beberapa salinan" adalah pola yang lebih buruk.
Rick James
4
Ini tidak bekerja jika Anda telah membuat objek PDOStatement antara dua baris tersebut (yaitu, dalam setiap situasi praktis). Untuk menutup koneksi, Anda harus mengatur objek PDO DAN objek PDOStatement ke null. Lihat di sini: php.net/manual/en/pdo.connections.php#114822
Ilmari
8

Ini lebih dari sekedar mengatur koneksi ke null. Itu mungkin yang dikatakan oleh dokumentasi, tapi itu bukan kebenaran untuk mysql. Koneksi akan bertahan sedikit lebih lama (Saya pernah mendengar 60-an, tetapi tidak pernah mengujinya)

Jika Anda ingin di sini penjelasan lengkapnya lihat komentar ini di koneksi https://www.php.net/manual/en/pdo.connections.php#114822

Untuk memaksa menutup koneksi, Anda harus melakukan sesuatu seperti

$this->connection = new PDO();
$this->connection->query('KILL CONNECTION_ID()');
$this->connection = null;
Jdahern
sumber
Terima kasih atas jawaban Anda. Pertanyaannya berasal dari beberapa waktu yang lalu tetapi hak Anda tentang koneksi.
Liam Sorsby
Saya sebenarnya tidak setuju bahwa mengotak-atik koneksi TCP melalui PHP adalah ide yang bagus. Semua penanganan koneksi TCP tingkat rendah disarikan sehingga kita hanya perlu berurusan dengan kelas dan objek tingkat tinggi selama runtime. PHP adalah bahasa berbasis permintaan (seperti yang mungkin Anda ketahui) sehingga mematikan koneksi yang berpotensi persisten ke dB kemungkinan akan mengakibatkan kesalahan / masalah yang tidak terduga bagi pengguna. Kasus penggunaan yang Anda tautkan kemungkinan besar mengakibatkan pengemudi menjaga koneksi tetap terbuka untuk digunakan oleh permintaan lain, jadi saya pikir ini adalah perilaku yang diharapkan.
Liam Sorsby
Jika Anda benar-benar melihat daftar proses di mysql, itu akan menunjukkan koneksi masih ada. Saya setuju Anda tidak boleh mengotak-atik koneksi TCP seperti ini, dan harus ada cara untuk memutuskan koneksi dengan benar. Tapi bukan itu masalahnya. Jadi, jika Anda benar-benar ingin memutuskan sambungan dari server, Anda harus melakukan sesuatu seperti ini. Menyetel koneksi ke null tidak memutuskan koneksi sesuai dengan apa yang dikatakan dokumen.
Jdahern
Saya telah menemukan penjelasan ini: stackoverflow.com/a/18277327/1315873
Fil
7

Saya membuat kelas turunan untuk memiliki instruksi yang lebih mendokumentasikan diri daripada "$ 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;
    }
}

Jadi saya dapat memanggil kode saya antara:

$conn=CMyPDO::getNewConnection();
// my code
CMyPDO::closeConnection($conn);
Fil
sumber
1
Anda dapat membuat metode CMyPDO :: __ construct () menjadi privat dan menggunakan pola tunggal di sana ..
Aditya Hajare
Ya, itu mungkin. Anda juga perlu menetapkan informasi koneksi dengan metode lain jika Anda menggunakan lebih dari satu database dalam satu waktu. Perbedaannya minimal, hanya saja Anda memiliki sedikit instruksi lebih lama untuk memanggil metode instance.
Fil
@AdityaHajare Anda tidak dapat membuat metode publik dari superclass menjadi privat dalam subkelas ..
nickdnk
@nickdnk, Anda benar. Yang saya maksud adalah membuat kelas CMyPDO mandiri (tanpa membuatnya memperpanjang PDO) dan kemudian membuat instance database di dalam konstruktor pribadi CMyPDO (kelas PDO baru ($ dsn, $ dbuser, $ dbpass);) memastikan hanya satu contoh tersedia di seluruh aplikasi (Pola Desain Singleton).
Aditya Hajare
1
@Fil Tetapi kode "luar" closeConnectionseharusnya tidak menyadari bahwa ia perlu menyalin referensi ke variabel alih-alih menugaskan objek. Dengan kata lain, cara Anda untuk mencoba membuat kode fungsi PDO dekat memiliki efek samping yang buruk, membuatnya tidak dapat diandalkan. Satu-satunya cara untuk melakukannya adalah closeConnectiondengan memeriksa berapa banyak referensi ke objek PDO yang ada dalam kode, dan melempar jika ada lebih dari 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

Contoh lengkapnya, dengan custom class PDO2.

yo lo
sumber
1
Harap hapus try catch dari kode Anda atau tambahkan lemparan baru ke dalam seperti yang ditunjukkan di sini . Saat ini kode Anda menyalahgunakan pengecualian dan pelaporan kesalahan secara umum
Akal Sehat Anda