วิธีการดีบักการสืบค้นฐานข้อมูล PDO


140

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

คำสั่ง PDO ที่เตรียมไว้นั้นเร็วขึ้นและดีขึ้นและปลอดภัยขึ้น แต่สิ่งหนึ่งที่รบกวนฉัน: ฉันไม่เคยเห็นข้อความค้นหาสุดท้ายเมื่อส่งไปยังฐานข้อมูล เมื่อฉันได้รับข้อผิดพลาดเกี่ยวกับไวยากรณ์ในบันทึก Apache หรือไฟล์บันทึกที่กำหนดเอง (ฉันบันทึกข้อผิดพลาดภายในcatchบล็อก) ฉันไม่เห็นข้อความค้นหาที่ทำให้เกิดปัญหา

มีวิธีจับแบบสอบถาม SQL ที่สมบูรณ์ส่งโดย PDO ไปยังฐานข้อมูลและบันทึกลงในไฟล์หรือไม่


4
มันถูกบันทึกไว้ในไฟล์: /var/log/mysql/*. พารามิเตอร์ผูกพัน PDO ไม่สามารถทำให้เกิดข้อผิดพลาดทางไวยากรณ์ดังนั้นสิ่งที่คุณต้องมีคือแบบสอบถาม SQL ที่เตรียมไว้
Xeoncross

1
ดูรหัสในstackoverflow.com/questions/210564/… (ไม่ใช่คำตอบที่ยอมรับ) ไม่ใช่ว่ามีการอัพเดทเล็กน้อย
Mawg กล่าวว่าคืนสถานะโมนิก้า

1
ง่าย ๆ หนึ่งบรรทัดผ่านนักแต่งเพลง: github.com/panique/pdo-debug
Sliq

2
คำตอบของ Xeoncross ช่วยฉัน นี่คือบทความที่อธิบายวิธีเปิดใช้งานคุณลักษณะนี้ เป็นค่าเริ่มต้นในการติดตั้งเซิร์ฟเวอร์จำนวนมาก pontikis.net/blog/how-and-when-to-enable-mysql-logs
mrbinky3000

2
ลองด้วยvar_dump($pdo_instance->debugDumpParams())
Daniel Petrovaliev

คำตอบ:


99

คุณพูดแบบนี้:

ฉันไม่เคยเห็นข้อความค้นหาสุดท้ายที่ส่งไปยังฐานข้อมูล

จริง ๆ แล้วเมื่อใช้คำสั่งที่เตรียมไว้ไม่มีสิ่งเช่น " แบบสอบถามสุดท้าย " :

  • ขั้นแรกข้อความจะถูกส่งไปยังฐานข้อมูลและเตรียมไว้ที่นั่น
    • ฐานข้อมูลแยกวิเคราะห์แบบสอบถามและสร้างการเป็นตัวแทนภายในของมัน
  • และเมื่อคุณผูกตัวแปรและดำเนินการคำสั่งเฉพาะตัวแปรจะถูกส่งไปยังฐานข้อมูล
    • และฐานข้อมูล "แทรก" ค่าลงในการเป็นตัวแทนภายในของคำสั่ง


ดังนั้นเพื่อตอบคำถามของคุณ:

มีวิธีจับแบบสอบถาม SQL ที่สมบูรณ์ส่งโดย PDO ไปยังฐานข้อมูลและบันทึกลงในไฟล์หรือไม่

ไม่: เนื่องจากไม่มี " แบบสอบถาม SQL ที่สมบูรณ์ " ทุกที่จึงไม่มีวิธีการจับภาพ


สิ่งที่ดีที่สุดที่คุณสามารถทำได้เพื่อจุดประสงค์ในการดีบั๊กคือ "สร้างแบบสอบถาม SQL" ของจริง "ใหม่โดยการฉีดค่าลงในสตริง SQL ของคำสั่ง

สิ่งที่ฉันมักจะทำในสถานการณ์เช่นนี้คือ:

  • echo โค้ด SQL ที่สอดคล้องกับคำสั่งด้วยตัวยึดตำแหน่ง
  • และใช้var_dump (หรือเทียบเท่า)หลังจากนั้นเพื่อแสดงค่าของพารามิเตอร์
  • โดยทั่วไปจะเพียงพอที่จะเห็นข้อผิดพลาดที่เป็นไปได้แม้ว่าคุณจะไม่มีแบบสอบถาม "ของจริง" ที่คุณสามารถดำเนินการ

มันไม่ได้ยอดเยี่ยมเมื่อพูดถึงการแก้ไขข้อบกพร่อง แต่นั่นเป็นราคาของข้อความสั่งที่เตรียมไว้และข้อดีที่พวกเขานำ


1
คำอธิบายที่ดี - ขอบคุณ เห็นได้ชัดว่าฉันมีเพียงความคิดที่คลุมเครือเกี่ยวกับวิธีการทำงานนี้ ฉันคิดว่าเมื่อคำสั่งถูกจัดเตรียมวัตถุที่เกิดขึ้นมีแฮหรือ ID ตัวเลขที่สามารถส่งกลับไปยังฐานข้อมูลที่มีพารามิเตอร์ที่จะเสียบเข้า
Nathan Long

ยินดีต้อนรับคุณ :-) ;;; ฉันไม่ทราบว่าจะมีการใช้รายละเอียดอย่างไร แต่ฉันคิดว่ามันเป็นเช่นนั้น - ผลลัพธ์ก็เป็นเช่นนั้นอย่างไรก็ตาม ;; นั่นเป็นหนึ่งในสิ่งที่ดีพร้อมคำสั่งที่เตรียมไว้: หากคุณต้องดำเนินการแบบสอบถามเดียวกันหลายครั้งมันจะถูกส่งไปยังฐานข้อมูลและจัดทำเพียงครั้งเดียว: สำหรับการดำเนินการแต่ละครั้งจะมีการส่งข้อมูลเท่านั้น
Pascal MARTIN

1
ปรับปรุง: Aaron Patterson พูดถึงที่ Railsconf 2011 ว่าเขาได้เพิ่มแถลงการณ์ที่เตรียมไว้ให้กับ Rails แต่ประโยชน์ที่ได้รับนั้นหนักกว่า PostgreSQL มากกว่าใน MySQL เขากล่าวว่าเป็นเพราะ MySQL ไม่ได้สร้างแผนแบบสอบถามจริง ๆ จนกว่าคุณจะดำเนินการแบบสอบถามที่เตรียมไว้
Nathan Long

85

ค้นหาในบันทึกฐานข้อมูล

แม้ว่าPascal MARTINนั้นถูกต้องแล้ว PDO จะไม่ส่งการสืบค้นที่สมบูรณ์ไปยังฐานข้อมูลทั้งหมดในคราวเดียว แต่ข้อเสนอแนะของryeguyในการใช้ฟังก์ชั่นการบันทึกของ DB ทำให้ฉันเห็นการสืบค้นที่สมบูรณ์และดำเนินการโดยฐานข้อมูล

นี่คือวิธี: (คำแนะนำเหล่านี้ใช้สำหรับ MySQL บนเครื่อง Windows - ระยะของคุณอาจแตกต่างกันไป)

  • ในmy.iniภายใต้[mysqld]ส่วนให้เพิ่มlogคำสั่งเช่นlog="C:\Program Files\MySQL\MySQL Server 5.1\data\mysql.log"
  • รีสตาร์ท MySQL
  • มันจะเริ่มบันทึกทุกแบบสอบถามในไฟล์นั้น

ไฟล์นั้นจะเติบโตอย่างรวดเร็วดังนั้นโปรดลบออกแล้วปิดการบันทึกเมื่อคุณทำการทดสอบเสร็จแล้ว


1
แค่ทราบ - ฉันต้องหนีเครื่องหมายทับใน my.ini ดังนั้นรายการของฉันดูเหมือน log = "C: \\ temp \\ MySQL \\ mysql.log"
จิม

4
นี้อาจPDO::ATTR_EMULATE_PREPARESทำงานขึ้นอยู่กับการตั้งค่าของ ดูคำตอบนี้สำหรับข้อมูลเพิ่มเติม: stackoverflow.com/questions/10658865/#answer-10658929
webbiedave

23
ฉันเกลียด PDO เพราะสิ่งนี้
Salman

1
@webbiedave - โอ้ว้าว! คำตอบที่เชื่อมโยงของคุณแสดงว่าคำตอบของฉันใช้ได้เฉพาะเมื่อ PDO ไม่ทำงานอย่างเหมาะสม แต่ส่งคำค้นหาทั้งหมดเพื่อให้เข้ากันได้กับ MySQL รุ่นเก่าหรือไดรเวอร์เก่า น่าสนใจ
Nathan Long

13
ใน MySQL 5.5+ คุณต้องแทนgeneral_log logดูdev.mysql.com/doc/refman/5.5/en/query-log.html
Adrian Macneil

18

แน่ใจว่าคุณสามารถแก้ไขข้อบกพร่องโดยใช้โหมดนี้{{ PDO::ATTR_ERRMODE }} เพียงเพิ่มบรรทัดใหม่ก่อนที่จะค้นหาของคุณแล้วคุณจะแสดงบรรทัดการแก้ปัญหา

$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$db->query('SELECT *******');  

คุณจะไม่โทร->queryเมื่อใช้งบเตรียม?
EoghanM

ขอบคุณที่ช่วยฉันมาก! :)
unbreak

17

อาจเป็นสิ่งที่คุณต้องการจะใช้debugDumpParams ()ในการจัดการคำสั่ง คุณสามารถรันได้ตลอดเวลาหลังจากเชื่อมโยงค่ากับแบบสอบถามที่เตรียมไว้ (ไม่จำเป็นต้องexecute()มีคำสั่ง)

มันไม่ได้สร้างคำสั่งที่เตรียมไว้ให้คุณ แต่มันจะแสดงพารามิเตอร์ของคุณ


2
ปัญหาเดียวคือมันส่งออกการแก้ปัญหาแทนการจัดเก็บภายในโดยไม่ต้อง 'Echoing' มัน ฉันไม่สามารถบันทึกมันด้วยวิธีนี้
Ricardo Martins

3
คุณสามารถใช้บัฟเฟอร์ออก (ob_start () ... )) เพื่อเก็บผลลัพธ์และเข้าสู่ระบบ
Cranio

bugs.php.net/bug.php?id=52384 ได้รับการแก้ไขใน 7.1 คุณสามารถดูค่า :) บิตช้า แต่มันเป็น php
Sander Visser

12

โพสต์เก่า แต่บางคนอาจพบว่ามีประโยชน์

function pdo_sql_debug($sql,$placeholders){
    foreach($placeholders as $k => $v){
        $sql = preg_replace('/:'.$k.'/',"'".$v."'",$sql);
    }
    return $sql;
}

1
สำหรับฟังก์ชั่นที่คล้ายกันที่สามารถจัดการพารามิเตอร์ตัวเลขได้โปรดดูคำตอบของฉัน (ขอบคุณผู้แสดงความคิดเห็นใน php.net)
Matt Browne

9

นี่คือฟังก์ชั่นเพื่อดูว่า SQL ที่มีประสิทธิภาพจะเป็นอย่างไร adpated จากความคิดเห็นโดย "ทำเครื่องหมาย" ที่php.net :

function sql_debug($sql_string, array $params = null) {
    if (!empty($params)) {
        $indexed = $params == array_values($params);
        foreach($params as $k=>$v) {
            if (is_object($v)) {
                if ($v instanceof \DateTime) $v = $v->format('Y-m-d H:i:s');
                else continue;
            }
            elseif (is_string($v)) $v="'$v'";
            elseif ($v === null) $v='NULL';
            elseif (is_array($v)) $v = implode(',', $v);

            if ($indexed) {
                $sql_string = preg_replace('/\?/', $v, $sql_string, 1);
            }
            else {
                if ($k[0] != ':') $k = ':'.$k; //add leading colon if it was left out
                $sql_string = str_replace($k,$v,$sql_string);
            }
        }
    }
    return $sql_string;
}

ทำไม "มาร์ค" ใช้ลำไส้ใหญ่ก่อน $ k ในstr_replace(":$k" ....? ดัชนีเชื่อมโยงมีอยู่แล้วในอาร์เรย์ $ params
Alan

เป็นคำถามที่ดี ... นี่อาจอธิบายได้ว่ามันstackoverflow.com/questions/9778887/... โดยส่วนตัวแล้วฉันใช้ฟังก์ชั่นนี้เพื่อดีบักข้อความค้นหา Doctrine และฉันคิดว่า Doctrine ใช้ตัวเลขแทนพารามิเตอร์ที่ตั้งชื่อดังนั้นฉันจึงไม่สังเกตเห็นปัญหานี้ ฉันอัปเดตฟังก์ชั่นเพื่อให้สามารถทำงานได้ทั้งที่มีและไม่มีโคลอนนำ
Matt Browne

ทราบว่าการแก้ปัญหานี้แทนด้วย:name_long :nameอย่างน้อยถ้ามาก่อน:name :name_longแถลงการณ์ที่ MySQL เตรียมไว้สามารถจัดการเรื่องนี้ได้อย่างถูกต้องดังนั้นอย่าให้คุณสับสน
Zim84

8

ไม่แบบสอบถาม PDO ไม่ได้จัดเตรียมไว้ที่ฝั่งไคลเอ็นต์ PDO เพียงส่งแบบสอบถาม SQL และพารามิเตอร์ไปยังเซิร์ฟเวอร์ฐานข้อมูล ฐานข้อมูลเป็นสิ่งที่ไม่ทดแทน (ของ?'s) คุณมีสองทางเลือก:

  • ใช้ฟังก์ชั่นการบันทึกข้อมูลของคุณ (แต่ถึงอย่างนั้นมันก็มักจะแสดงเป็นสองข้อความแยกกัน (เช่น "ไม่ใช่ขั้นสุดท้าย") อย่างน้อยกับ Postgres)
  • ส่งออกแบบสอบถาม SQL และพารามิเตอร์และแยกชิ้นส่วนด้วยกัน

ฉันไม่เคยคิดที่จะตรวจสอบบันทึกของฐานข้อมูล ฉันแหย่อยู่ในไดเรกทอรี MySQL และไม่เห็นไฟล์บันทึกใด ๆ แต่บางทีการบันทึกเป็นตัวเลือกที่ฉันต้องเปิดที่ไหนสักแห่ง
นาธานลอง

ใช่คุณต้องเปิดใช้งาน ฉันไม่ทราบรายละเอียดเฉพาะ แต่ตามค่าเริ่มต้นแล้วจะไม่บันทึกทุกข้อความค้นหา
ryeguy

5

เกือบจะไม่มีอะไรพูดเกี่ยวกับข้อผิดพลาดในการแสดงยกเว้นตรวจสอบบันทึกข้อผิดพลาด แต่มีฟังก์ชั่นที่ค่อนข้างมีประโยชน์:

<?php
/* Provoke an error -- bogus SQL syntax */
$stmt = $dbh->prepare('bogus sql');
if (!$stmt) {
    echo "\PDO::errorInfo():\n";
    print_r($dbh->errorInfo());
}
?>

( ลิงค์แหล่งที่มา )

เป็นที่ชัดเจนว่ารหัสนี้สามารถแก้ไขได้เพื่อใช้เป็นข้อความข้อยกเว้นหรือการจัดการข้อผิดพลาดชนิดอื่น ๆ


2
นี่เป็นวิธีที่ผิด PDO ฉลาดพอที่จะทำให้โค้ดนี้ไร้ประโยชน์ เพียงบอกให้โยนข้อยกเว้นในข้อผิดพลาด PHP จะทำส่วนที่เหลือให้ดีกว่าฟังก์ชันที่ จำกัด นี้ นอกจากนี้โปรดเรียนรู้ที่จะไม่พิมพ์ข้อผิดพลาดทั้งหมดลงในเบราว์เซอร์โดยตรง มีวิธีที่ดีกว่า
สามัญสำนึกของคุณ

3
นั่นเป็นเอกสารอย่างเป็นทางการและแน่นอนว่าไม่มีใครพิมพ์ข้อผิดพลาดในการผลิตอีกครั้งนี่เป็นตัวอย่างจากเว็บไซต์ทางการ (php.net) ดูลิงค์ด้านล่างตัวอย่างรหัส และแน่นอนดีกว่าคือใช้ params เพิ่มเติม $ db-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION) ภายในการเริ่มต้น PDO แต่น่าเสียดายที่คุณไม่สามารถเข้าถึงรหัสนั้นได้
Zippp

4

เช่นคุณมีคำสั่ง pdo นี้:

$query="insert into tblTest (field1, field2, field3)
values (:val1, :val2, :val3)";
$res=$db->prepare($query);
$res->execute(array(
  ':val1'=>$val1,
  ':val2'=>$val2,
  ':val3'=>$val3,
));

ตอนนี้คุณสามารถรับแบบสอบถามที่ถูกเรียกใช้งานโดยการกำหนดอาร์เรย์ดังนี้:

$assoc=array(
  ':val1'=>$val1,
  ':val2'=>$val2,
  ':val3'=>$val3,
);
$exQuery=str_replace(array_keys($assoc), array_values($assoc), $query);
echo $exQuery;

1
ทำงานให้ฉัน คุณมีข้อผิดพลาดในตัวอย่างโค้ดที่สอง: ));ควรเป็น);(วงเล็บเดียวเท่านั้น)
Jasom Dotnet

2

ค้นหาอินเทอร์เน็ตฉันพบว่านี่เป็นวิธีการแก้ปัญหาที่ยอมรับได้ คลาสอื่นจะใช้แทนฟังก์ชัน PDO และ PDO จะถูกเรียกผ่านการเรียกใช้ฟังก์ชั่นเวทย์มนตร์ ฉันไม่แน่ใจว่าสิ่งนี้จะสร้างปัญหาประสิทธิภาพการทำงานที่ร้ายแรง แต่สามารถใช้งานได้จนกว่าจะมีการเพิ่มคุณสมบัติการบันทึกที่เหมาะสมลงใน PDO

ดังนั้นตามหัวข้อนี้คุณสามารถเขียน wrapper สำหรับการเชื่อมต่อ PDO ของคุณซึ่งสามารถบันทึกและส่งข้อยกเว้นเมื่อคุณได้รับข้อผิดพลาด

นี่คือตัวอย่างง่ายๆ:

class LoggedPDOSTatement extends PDOStatement    {

function execute ($array)    {
    parent::execute ($array);
    $errors = parent::errorInfo();
    if ($errors[0] != '00000'):
        throw new Exception ($errors[2]);
    endif;
  }

}

เพื่อให้คุณสามารถใช้คลาสนั้นแทน PDOStatement:

$this->db->setAttribute (PDO::ATTR_STATEMENT_CLASS, array ('LoggedPDOStatement', array()));

นี่คือการใช้งานมัณฑนากร PDO ที่กล่าวถึง:

class LoggedPDOStatement    {

function __construct ($stmt)    {
    $this->stmt = $stmt;
}

function execute ($params = null)    {
    $result = $this->stmt->execute ($params); 
    if ($this->stmt->errorCode() != PDO::ERR_NONE):
        $errors = $this->stmt->errorInfo();
        $this->paint ($errors[2]);
    endif;
    return $result;
}

function bindValue ($key, $value)    {
    $this->values[$key] = $value;    
    return $this->stmt->bindValue ($key, $value);
}

function paint ($message = false)    {
    echo '<pre>';
    echo '<table cellpadding="5px">';
    echo '<tr><td colspan="2">Message: ' . $message . '</td></tr>';
    echo '<tr><td colspan="2">Query: ' . $this->stmt->queryString . '</td></tr>';
    if (count ($this->values) > 0):
    foreach ($this->values as $key => $value):
    echo '<tr><th align="left" style="background-color: #ccc;">' . $key . '</th><td>' . $value . '</td></tr>';
    endforeach;
    endif;
    echo '</table>';
    echo '</pre>';
}

function __call ($method, $params)    {
    return call_user_func_array (array ($this->stmt, $method), $params); 
}

}

2

ในการเข้าสู่ระบบ MySQL ในWAMPคุณจะต้องแก้ไข my.ini (เช่นใต้ wamp \ bin \ mysql \ mysql5.6.17 \ my.ini)

และเพิ่มไปที่[mysqld]:

general_log = 1
general_log_file="c:\\tmp\\mysql.log"

1

นี่คือฟังก์ชั่นที่ฉันทำเพื่อส่งคืนเคียวรี SQL ด้วยพารามิเตอร์ "ที่แก้ไขแล้ว"

function paramToString($query, $parameters) {
    if(!empty($parameters)) {
        foreach($parameters as $key => $value) {
            preg_match('/(\?(?!=))/i', $query, $match, PREG_OFFSET_CAPTURE);
            $query = substr_replace($query, $value, $match[0][1], 1);
        }
    }
    return $query;
    $query = "SELECT email FROM table WHERE id = ? AND username = ?";
    $values = [1, 'Super'];

    echo paramToString($query, $values);

สมมติว่าคุณดำเนินการเช่นนี้

$values = array(1, 'SomeUsername');
$smth->execute($values);

ฟังก์ชั่นนี้ไม่ได้เพิ่มราคาให้กับแบบสอบถาม แต่จะทำงานให้ฉัน


0

ปัญหาที่ฉันมีกับวิธีการตรวจจับการยกเว้น PDO สำหรับจุดประสงค์ในการตรวจแก้จุดบกพร่องคือมันตรวจจับ PDO exemptions (duh) เท่านั้น แต่ไม่พบข้อผิดพลาดทางไวยากรณ์ที่ลงทะเบียนเป็นข้อผิดพลาด php (ฉันไม่แน่ใจว่าทำไมถึงเป็น แต่ " ทำไม "ไม่เกี่ยวข้องกับการแก้ปัญหา) การเรียก PDO ของฉันทั้งหมดมาจากคลาสโมเดลตารางเดียวที่ฉันขยายสำหรับการโต้ตอบทั้งหมดของฉันกับตารางทั้งหมด ... สิ่งที่ซับซ้อนนี้เมื่อฉันพยายามที่จะแก้จุดบกพร่องรหัสเพราะข้อผิดพลาดจะลงทะเบียนบรรทัดของรหัส php โทร แต่ไม่ได้บอกฉันว่าโทรมาจากไหน ฉันใช้รหัสต่อไปนี้เพื่อแก้ไขปัญหานี้:

/**
 * Executes a line of sql with PDO.
 * 
 * @param string $sql
 * @param array $params
 */
class TableModel{
    var $_db; //PDO connection
    var $_query; //PDO query

    function execute($sql, $params) { 
        //we're saving this as a global, so it's available to the error handler
        global $_tm;
        //setting these so they're available to the error handler as well
        $this->_sql = $sql;
        $this->_paramArray = $params;            

        $this->_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->_query = $this->_db->prepare($sql);

        try {
            //set a custom error handler for pdo to catch any php errors
            set_error_handler('pdoErrorHandler');

            //save the table model object to make it available to the pdoErrorHandler
            $_tm = $this;
            $this->_query->execute($params);

            //now we restore the normal error handler
            restore_error_handler();
        } catch (Exception $ex) {
            pdoErrorHandler();
            return false;
        }            
    }
}

ดังนั้นรหัสข้างต้นจับข้อผิดพลาดทั้ง PDO และข้อผิดพลาดทางไวยากรณ์ php และปฏิบัติต่อพวกเขาในลักษณะเดียวกัน ตัวจัดการข้อผิดพลาดของฉันมีลักษณะเช่นนี้:

function pdoErrorHandler() {
    //get all the stuff that we set in the table model
    global $_tm;
    $sql = $_tm->_sql;
    $params = $_tm->_params;
    $query = $tm->_query;

    $message = 'PDO error: ' . $sql . ' (' . implode(', ', $params) . ") \n";

    //get trace info, so we can know where the sql call originated from
    ob_start();
    debug_backtrace(); //I have a custom method here that parses debug backtrace, but this will work as well
    $trace = ob_get_clean();

    //log the error in a civilized manner
    error_log($message);

    if(admin(){
        //print error to screen based on your environment, logged in credentials, etc.
        print_r($message);
    }
}

หากใครมีแนวคิดที่ดีกว่าเกี่ยวกับวิธีรับข้อมูลที่เกี่ยวข้องกับตัวจัดการข้อผิดพลาดของฉันมากกว่าการตั้งค่าแบบจำลองตารางเป็นตัวแปรทั่วโลกฉันยินดีที่จะได้ยินและแก้ไขรหัสของฉัน


0

รหัสนี้ใช้งานได้ดีสำหรับฉัน:

echo str_replace(array_keys($data), array_values($data), $query->queryString);

อย่าลืมแทนที่ $ data และ $ query ด้วยชื่อของคุณ


0

ฉันใช้คลาสนี้เพื่อดีบัก PDO (พร้อมLog4PHP )

<?php

/**
 * Extends PDO and logs all queries that are executed and how long
 * they take, including queries issued via prepared statements
 */
class LoggedPDO extends PDO
{

    public static $log = array();

    public function __construct($dsn, $username = null, $password = null, $options = null)
    {
        parent::__construct($dsn, $username, $password, $options);
    }

    public function query($query)
    {
        $result = parent::query($query);
        return $result;
    }

    /**
     * @return LoggedPDOStatement
     */
    public function prepare($statement, $options = NULL)
    {
        if (!$options) {
            $options = array();
        }
        return new \LoggedPDOStatement(parent::prepare($statement, $options));
    }
}

/**
 * PDOStatement decorator that logs when a PDOStatement is
 * executed, and the time it took to run
 * @see LoggedPDO
 */
class LoggedPDOStatement
{

    /**
     * The PDOStatement we decorate
     */
    private $statement;
    protected $_debugValues = null;

    public function __construct(PDOStatement $statement)
    {
        $this->statement = $statement;
    }

    public function getLogger()
    {
        return \Logger::getLogger('PDO sql');
    }

    /**
     * When execute is called record the time it takes and
     * then log the query
     * @return PDO result set
     */
    public function execute(array $params = array())
    {
        $start = microtime(true);
        if (empty($params)) {
            $result = $this->statement->execute();
        } else {
            foreach ($params as $key => $value) {
                $this->_debugValues[$key] = $value;
            }
            $result = $this->statement->execute($params);
        }

        $this->getLogger()->debug($this->_debugQuery());

        $time = microtime(true) - $start;
        $ar = (int) $this->statement->rowCount();
        $this->getLogger()->debug('Affected rows: ' . $ar . ' Query took: ' . round($time * 1000, 3) . ' ms');
        return $result;
    }

    public function bindValue($parameter, $value, $data_type = false)
    {
        $this->_debugValues[$parameter] = $value;
        return $this->statement->bindValue($parameter, $value, $data_type);
    }

    public function _debugQuery($replaced = true)
    {
        $q = $this->statement->queryString;

        if (!$replaced) {
            return $q;
        }

        return preg_replace_callback('/:([0-9a-z_]+)/i', array($this, '_debugReplace'), $q);
    }

    protected function _debugReplace($m)
    {
        $v = $this->_debugValues[$m[0]];

        if ($v === null) {
            return "NULL";
        }
        if (!is_numeric($v)) {
            $v = str_replace("'", "''", $v);
        }

        return "'" . $v . "'";
    }

    /**
     * Other than execute pass all other calls to the PDOStatement object
     * @param string $function_name
     * @param array $parameters arguments
     */
    public function __call($function_name, $parameters)
    {
        return call_user_func_array(array($this->statement, $function_name), $parameters);
    }
}

0

ฉันได้สร้างโครงการ / พื้นที่เก็บข้อมูลนักแต่งเพลงที่ทันสมัยสำหรับตรงนี้:

PDO-การแก้ปัญหา

ค้นหาโครงการบ้าน GitHub ที่นี่ให้ดูโพสต์บล็อกอธิบายได้ที่นี่ หนึ่งบรรทัดที่จะเพิ่มใน composer.json ของคุณจากนั้นคุณสามารถใช้สิ่งนี้:

echo debugPDO($sql, $parameters);

$ sql เป็นคำสั่ง SQL แบบ raw, พารามิเตอร์ $ เป็นอาเรย์ของพารามิเตอร์ของคุณ: คีย์คือชื่อตัวยึดตำแหน่ง (": user_id") หรือหมายเลขของพารามิเตอร์ที่ไม่มีชื่อ ("?"), ค่าคือ .. ความคุ้มค่า

ตรรกะที่อยู่เบื้องหลัง: สคริปต์นี้จะทำการแบ่งพารามิเตอร์และแทนที่ลงในสตริง SQL ที่ระบุ เรียบง่าย แต่มีประสิทธิภาพสูงถึง 99% ของการใช้เคสของคุณ หมายเหตุ: นี่เป็นเพียงการจำลองพื้นฐานไม่ใช่การดีบัก PDO จริง (เนื่องจากไม่สามารถทำได้เนื่องจาก PHP จะส่ง SQL ดิบและพารามิเตอร์ไปยังเซิร์ฟเวอร์ MySQL แยกต่างหาก)

ขอบคุณมากสำหรับbigwebguyและMikeจากเธรด StackOverflow การรับสตริงเคียวรี SQL แบบ raw จาก PDOสำหรับการเขียนฟังก์ชันหลักทั้งหมดที่อยู่เบื้องหลังสคริปต์นี้ ขนาดใหญ่ขึ้น!


0

วิธีการดีบักการสืบค้นฐานข้อมูล PDO mysql ใน Ubuntu

TL; DR บันทึกการสืบค้นทั้งหมดของคุณและจัดทำบันทึก mysql

คำแนะนำเหล่านี้สำหรับติดตั้ง Ubuntu 14.04 ของฉัน ออกคำสั่งlsb_release -aเพื่อรับรุ่นของคุณ การติดตั้งของคุณอาจแตกต่างกัน

เปิดการเข้าสู่ระบบใน mysql

  1. ไปที่เซิร์ฟเวอร์ dev cmd line ของคุณ
  2. cd /etc/mysqlไดเรกทอรีเปลี่ยน my.cnfคุณควรจะเห็นไฟล์ที่เรียกว่า นั่นคือไฟล์ที่เราจะเปลี่ยน
  3. cat my.cnf | grep general_logตรวจสอบคุณอยู่ในสถานที่ที่เหมาะสมโดยการพิมพ์ สิ่งนี้จะกรองmy.cnfไฟล์ให้คุณ คุณควรจะเห็นรายการที่สอง: &&#general_log_file = /var/log/mysql/mysql.log#general_log = 1
  4. ยกเลิกการใส่ข้อคิดเห็นสองบรรทัดเหล่านั้นและบันทึกผ่านเครื่องมือแก้ไขที่คุณเลือก
  5. MySQL sudo service mysql restartเริ่มต้นใหม่:
  6. คุณอาจต้องรีสตาร์ทเว็บเซิร์ฟเวอร์ของคุณด้วย (ฉันจำลำดับที่ใช้ไม่ได้) สำหรับการติดตั้งของฉันที่ sudo service nginx restartNginx:

เยี่ยมมาก! คุณทุกชุด. ตอนนี้สิ่งที่คุณต้องทำคือแนบไฟล์บันทึกเพื่อที่คุณจะได้เห็น PDO สอบถามว่าแอปของคุณทำแบบเรียลไทม์

ปรับแต่งบันทึกเพื่อดูคำถามของคุณ

ป้อนคำสั่งtail -f /var/log/mysql/mysql.logนี้

ผลลัพธ์ของคุณจะมีลักษณะดังนี้:

73 Connect  xyz@localhost on your_db
73 Query    SET NAMES utf8mb4
74 Connect  xyz@localhost on your_db
75 Connect  xyz@localhost on your_db
74 Quit 
75 Prepare  SELECT email FROM customer WHERE email=? LIMIT ?
75 Execute  SELECT email FROM customer WHERE email='a@b.co' LIMIT 5
75 Close stmt   
75 Quit 
73 Quit 

ข้อความค้นหาใหม่ ๆ ที่แอปของคุณสร้างจะปรากฏขึ้นโดยอัตโนมัติตราบใดที่คุณยังคงปรับแต่งบันทึก cmd/ctrl cเพื่อออกจากหางตี

หมายเหตุ

  1. ระวัง: ไฟล์บันทึกนี้อาจมีขนาดใหญ่มาก ฉันใช้สิ่งนี้กับเซิร์ฟเวอร์ผู้พัฒนาของฉันเท่านั้น
  2. ไฟล์บันทึกมีขนาดใหญ่เกินไป? ตัดมัน หมายความว่าไฟล์ยังคงอยู่ แต่เนื้อหาจะถูกลบ truncate --size 0 mysql.log.
  3. เจ๋งที่ล็อกไฟล์แสดงรายการการเชื่อมต่อ mysql ฉันรู้ว่าหนึ่งในนั้นมาจากรหัส mysqli ดั้งเดิมที่ฉันกำลังเปลี่ยน ที่สามมาจากการเชื่อมต่อ PDO ใหม่ของฉัน อย่างไรก็ตามไม่แน่ใจว่าที่สองมาจากไหน หากคุณรู้วิธีการค้นหาที่รวดเร็วแจ้งให้เราทราบ

เครดิต & ขอบคุณ

ตะโกนออกมาอย่างมาก เป็นคำตอบของ Nathan Long ด้านบนเพื่อให้ Inspo คิดออกมาบน Ubuntu นอกจากนี้ยังให้dikirillสำหรับความคิดเห็นของเขาในโพสต์ของนาธานซึ่งทำให้ฉันไปแก้ปัญหานี้

รักคุณมาก!


0

ในสภาพแวดล้อม Debian NGINX ฉันทำสิ่งต่อไปนี้

ไป/etc/mysql/mysql.conf.dแก้ไขmysqld.cnfถ้าคุณพบว่าlog-error = /var/log/mysql/error.logเพิ่ม 2 บรรทัดต่อไปนี้ตะโกน

general_log_file        = /var/log/mysql/mysql.log
general_log             = 1

เพื่อดูบันทึกข้ามไป /var/log/mysqlและ tail -f mysql.log

โปรดอย่าลืมคอมเม้นต์บรรทัดเหล่านี้เมื่อคุณทำการแก้ไขข้อบกพร่องหากคุณอยู่ในสภาพแวดล้อมการผลิตmysql.logเนื่องจากไฟล์บันทึกนี้จะเติบโตอย่างรวดเร็วและอาจมีขนาดใหญ่มาก


ไม่ใช่ทุกคนที่ใช้ mysql
อัฒภาคหวั่น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.