PDO ปิดการเชื่อมต่อ


121

เป็นคำถามที่ค่อนข้างง่ายเกี่ยวกับ PDO เมื่อเทียบกับ MySQLi

ด้วย MySQLi เพื่อปิดการเชื่อมต่อคุณสามารถทำได้:

$this->connection->close();

อย่างไรก็ตามด้วย PDO จะระบุว่าคุณเปิดการเชื่อมต่อโดยใช้:

$this->connection = new PDO();

nullแต่เพื่อปิดการเชื่อมต่อที่คุณตั้งค่าให้

$this->connection = null;

ถูกต้องหรือไม่และจะทำให้การเชื่อมต่อ PDO ฟรีหรือไม่ (ฉันรู้ว่ามันทำตามที่ตั้งค่าเป็นnull) ฉันหมายถึงกับ MySQLi คุณต้องเรียกใช้ฟังก์ชัน ( close) เพื่อปิดการเชื่อมต่อ PDO ง่ายพอ ๆ= nullกับการตัดการเชื่อมต่อหรือไม่? หรือมีฟังก์ชั่นปิดการเชื่อมต่อหรือไม่


11
เหตุผลที่ฉันถามคือฉันไม่แน่ใจว่าฉันปิดการเชื่อมต่ออย่างถูกต้องหรือไม่ แต่ไม่เพียงแค่ทึ่งเท่านั้น
Liam Sorsby

2
การเชื่อมต่อฐานข้อมูลจะปิดโดยอัตโนมัติเมื่อสคริปต์ PHP ของคุณหยุดการทำงาน
Martin Bean

3
หากคุณใช้งานเสร็จแล้วทำไมไม่ดำเนินการต่อและยุติโดยเฉพาะอย่างยิ่งหากมีรหัสที่ใช้เวลานานเมื่อคุณโต้ตอบกับฐานข้อมูลเสร็จสิ้น แม้ว่าฉันจะไม่เห็นปัญหาในการรอให้สคริปต์เสร็จสิ้น (นอกเหนือจากการลดการเชื่อมต่อกับเซิร์ฟเวอร์ DB)
Kieran

3
github.com/php/php-src/blob/master/ext/pdo/pdo_dbh.cค้นหาด้วยตัวคุณเองว่ามันทำงานอย่างไร: P
Flosculus

23
สคริปต์ php ทั้งหมดไม่ได้ใช้งานสั้น มี php daemons อยู่ที่นั่น ฉันคิดว่านี่เป็นสิ่งที่ยอดเยี่ยมในการชี้แจงเป็นการส่วนตัว
datUser

คำตอบ:


146

ตามเอกสารคุณถูกต้อง ( http://php.net/manual/en/pdo.connections.php ):

การเชื่อมต่อยังคงใช้งานได้ตลอดอายุการใช้งานของออบเจ็กต์ PDOนั้น ในการปิดการเชื่อมต่อคุณต้องทำลายออบเจ็กต์โดยตรวจสอบให้แน่ใจว่าการอ้างอิงที่เหลือทั้งหมดถูกลบออก - คุณทำได้โดยกำหนดค่า NULL ให้กับตัวแปรที่เก็บอ็อบเจ็กต์ ถ้าคุณไม่ทำเช่นนี้อย่างชัดเจนPHP โดยอัตโนมัติจะปิดการเชื่อมต่อเมื่อสคริปต์ของคุณสิ้นสุดลง

โปรดทราบว่าหากคุณเริ่มต้นวัตถุ PDO เป็นการเชื่อมต่อแบบต่อเนื่องมันจะไม่ปิดการเชื่อมต่อโดยอัตโนมัติ


4
จะเกิดอะไรขึ้นถ้าฉันมีกระบวนการที่ไม่สิ้นสุด? เช่น websocket มีวิธีที่จะไม่ใช้การเชื่อมต่อแบบต่อเนื่องหรือไม่?
Rafael Moni

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 ไม่ควรเปิดตัว (มีให้สำหรับสคริปต์อื่น) แต่ไม่ได้ปิด
Benjamin

2
@tonix ฉันคิดอย่างนั้นใช่ ข้อความอ้างอิงจากคู่มือ PHP เกี่ยวกับการเชื่อมต่อแบบถาวร : " คำเตือนมีข้อควรระวังเพิ่มเติมอีกสองสามประการที่ควรคำนึงถึงเมื่อใช้การเชื่อมต่อแบบต่อเนื่องหนึ่งคือเมื่อใช้การล็อกตารางบนการเชื่อมต่อแบบต่อเนื่องหากสคริปต์ไม่ว่าด้วยเหตุผลใดก็ตามไม่สามารถคลายการล็อกได้ จากนั้นสคริปต์ที่ตามมาโดยใช้การเชื่อมต่อเดียวกันจะบล็อกไปเรื่อย ๆ และอาจต้องการให้คุณรีสตาร์ทเซิร์ฟเวอร์ httpd หรือเซิร์ฟเวอร์ฐานข้อมูล "
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 ฉันคิดว่ามันเป็นรูปแบบที่แย่มากโดยเฉพาะอย่างยิ่งเมื่อนักพัฒนาอาจเก็บสำเนาอ้างอิง pdo ไว้หลายชุด $ a = PDO ใหม่ (... ); $ b = $ ก; $ a = null; ที่นั่นวัตถุ PDO ของคุณจะยังคงเปิดตลอดไป (ในโปรแกรม php ที่มีลักษณะเหมือน daemon) โดยเฉพาะอย่างยิ่งเมื่อการอ้างอิง PDO เดินทางข้ามฟังก์ชันและคุณสมบัติของอ็อบเจ็กต์และคุณไม่แน่ใจว่าจะลบล้างสิ่งเหล่านี้ทั้งหมด
Gabriel

33
ควรมี -> ปิด () วิธีการบน PDO
Gabriel

5
อีกเหตุผลหนึ่งที่ไม่ชอบ PDO
José Carlos PHP

6
@ กาเบรียล - ฉันขอแนะนำว่า "การจัดเก็บสำเนาหลายชุด" เป็นรูปแบบที่แย่ยิ่งกว่า
Rick James

4
สิ่งนี้จะใช้ไม่ได้ถ้าคุณสร้างวัตถุ PDOStatement ระหว่างสองแถวนั้น (นั่นคือในทุกสถานการณ์จริง) ในการปิดการเชื่อมต่อคุณต้องตั้งค่าทั้งวัตถุ PDO และวัตถุ PDOStatement เป็น null ดูที่นี่: php.net/manual/en/pdo.connections.php#114822
Ilmari

8

มากกว่าการตั้งค่าการเชื่อมต่อเป็นโมฆะ นั่นอาจเป็นสิ่งที่เอกสารระบุ แต่นั่นไม่ใช่ความจริงสำหรับ mysql การเชื่อมต่อจะอยู่ได้นานขึ้นเล็กน้อย (ฉันเคยได้ยินยุค 60 แต่ไม่เคยทดสอบ)

หากคุณต้องการคำอธิบายแบบเต็มโปรดดูความคิดเห็นนี้ในการเชื่อมต่อhttps://www.php.net/manual/en/pdo.connections.php#114822

ในการบังคับให้ปิดการเชื่อมต่อคุณต้องทำสิ่งต่างๆเช่น

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

ขอบคุณสำหรับคำตอบ. คำถามเกิดขึ้นเมื่อไม่นานมานี้ แต่คุณมีสิทธิ์เกี่ยวกับการเชื่อมต่อ
Liam Sorsby

ฉันไม่เห็นด้วยจริงๆว่าการยุ่งกับการเชื่อมต่อ TCP ผ่าน PHP เป็นความคิดที่ดี การจัดการการเชื่อมต่อ TCP ระดับต่ำทั้งหมดถูกแยกออกไปดังนั้นเราจึงต้องจัดการกับคลาสและอ็อบเจ็กต์ระดับสูงในระหว่างรันไทม์ PHP เป็นภาษาตามคำขอ (ดังที่คุณอาจทราบ) ดังนั้นการฆ่าการเชื่อมต่อกับ dB ที่อาจเกิดขึ้นอย่างต่อเนื่องจึงอาจทำให้เกิดข้อผิดพลาด / ปัญหาที่ไม่คาดคิดสำหรับผู้ใช้ กรณีการใช้งานที่คุณเชื่อมโยงไปนั้นน่าจะเป็นผลมาจากไดรเวอร์ที่ยังคงเปิดการเชื่อมต่อแบบต่อเนื่องเพื่อใช้โดยคำขออื่นดังนั้นฉันจึงคิดว่าสิ่งนี้น่าจะเป็นพฤติกรรมที่คาดหวัง
Liam Sorsby

หากคุณดูรายการกระบวนการใน 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 :: __ สร้าง () วิธีการเป็นส่วนตัวและใช้รูปแบบซิงเกิลตันได้ที่นั่น ..
Aditya Hajare

ใช่มันเป็นไปได้ คุณต้องกำหนดข้อมูลการเชื่อมต่อด้วยวิธีการอื่นหากคุณใช้ฐานข้อมูลมากกว่าหนึ่งฐานข้อมูลในแต่ละครั้ง ความแตกต่างมีเพียงเล็กน้อยเพียงแค่คุณมีคำแนะนำในการเรียกใช้วิธีการอินสแตนซ์อีกต่อไป
Fil

@AdityaHajare คุณไม่สามารถสร้างเมธอดสาธารณะของซูเปอร์คลาสส่วนตัวในคลาสย่อยได้ ..
nickdnk

@nickdnk คุณพูดถูก สิ่งที่ฉันหมายถึงคือการสร้างคลาส CMyPDO แบบสแตนด์อโลน (โดยไม่ต้องขยาย PDO) จากนั้นสร้างอินสแตนซ์ของฐานข้อมูลภายในตัวสร้างส่วนตัวของ CMyPDO (PDO ใหม่ ($ dsn, $ dbuser, $ dbpass);) ให้แน่ใจว่ามีเพียงหนึ่ง อินสแตนซ์สามารถใช้ได้ตลอดทั้งแอปพลิเคชัน (รูปแบบการออกแบบซิงเกิลตัน)
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
โปรดลบลองจับจากรหัสของคุณหรือเพิ่มโยนภายในใหม่ตามที่แสดงที่นี่ ตอนนี้รหัสของคุณละเมิดทั้งข้อยกเว้นและการรายงานข้อผิดพลาดโดยทั่วไป
สามัญสำนึกของคุณ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.