2012-02-09 29 views
11

Tôi gặp sự cố lạ với php PDO và mysql.Cập nhật MySQL bằng PDO và tuyên bố chuẩn bị không hoạt động

Tôi có bảng sau:

create table test_table (id integer, value text); 

với một hàng duy nhất:

insert into test_table values (1, "asdf"); 

khi tôi cố gắng cập nhật hàng duy nhất này với một tuyên bố chuẩn bị, tôi có hành vi khác nhau tùy theo cú pháp tôi sử dụng:

// connection to db (common code) 
$dbh = new PDO("mysql:host=localhost;dbname=test", "myuser", "mypass"); 

======================================== =================

// WORKING 
$q = 'update test_table set id=1, value='.rand(0,99999).' where id=1'; 
$dbh->exec($q); 

=========================================== ==============

// WORKING 
$q = 'update test_table set value=:value where id=:id'; 
$par = array(
    "id" => 1, 
    "value" => rand(0,99999) 
); 
$sth = $dbh->prepare($q, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)); 
$sth->execute($par); 

============================= ============================

// NOT WORKING 
$q = 'update test_table set id=:id, value=:value where id=:id'; 
$par = array(
    "id" => 1, 
    "value" => rand(0,99999) 
); 
$sth = $dbh->prepare($q, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)); 
$sth->execute($par); 

Trong trường hợp thứ ba, trên máy chủ của tôi, bản cập nhật không được thực hiện trên hàng, không có lý do nào cũng không ngoại lệ/lỗi. Trên một máy chủ khác nó hoạt động. Tôi không tìm kiếm câu trả lời như: "và như vậy? Sử dụng triển khai đầu tiên hoặc thứ hai" :)

Tôi hỏi lý do triển khai thứ ba không hoạt động vì tôi đang di chuyển nhiều mã từ máy chủ sang một số khác (không phải mã của tôi) và nó chứa nhiều truy vấn như thế này và tôi không có thời gian để sửa chúng từng cái một. Trên máy chủ hiện tại, nó hoạt động và trên máy chủ mới nó không hoạt động.

Tại sao triển khai thứ ba không hoạt động? Có bất kỳ loại cấu hình cho php/pdo/mysql mà có thể ảnh hưởng đến hành vi này?

Cảm ơn.

Cập nhật: Cố gắng sqeeze ra thông báo lỗi:

$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

try { 
// NOT WORKING 
    $q = 'update test_table set id=:id, value=:value where id=:id'; 
    $par = array(
    "id" => 1, 
    "value" => rand(0,99999) 
); 
    $sth = $dbh->prepare($q, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)); 
    print_r($sth); 
    print_r($dbh->errorInfo()); 
} catch(PDOException $e) { 
    echo $e->getMessage(); 
} 

$sth->execute($par); 

Thực thi mã này trên cả hai máy chủ (làm việc và không làm việc):

PDOStatement Object 
(
    [queryString] => update test_table set id=:id, value=:value where id=:id 
) 
Array 
(
    [0] => 00000 
    [1] => 
    [2] => 
) 

Cập nhật 2

Xem xét bài kiểm tra tiếp theo này:

create table test_table (value0 text, value text); 
insert into test_table values ("1", "pippo"); 

// NOT WORKING 

$q = 'update test_table set value0=:value0, value=:value where value0=:value0'; 
$par = array(
    "value0" => "1", 
    "value" => rand(0, 839273) 
); 

create table test_table (value0 text, value text); 
insert into test_table values ("pippo", "1"); 

// WORKING 

$q = 'update test_table set value=:value, value0=:value0 where value=:value'; 
$par = array(
    "value" => "1", 
    "value0" => rand(0, 839273) 
); 

Đáng kinh ngạc phải không? Nghi ngờ của tôi bây giờ là tồn tại một số beahaviour cập nhật đặc biệt được thực hiện cho đầu tiên cột của mỗi bảng trên PDO + giữ chỗ xử lý.

+1

Bạn đang sử dụng: id cả để thay đổi giá trị của 'id' cũng như để xác định hàng. Bạn có chắc đó là điều bạn muốn làm không? – middus

+1

@middus: như anh ấy nói: "Tôi đang di chuyển rất nhiều mã từ máy chủ sang máy chủ khác (không phải mã của tôi) và nó chứa nhiều truy vấn như thế này và tôi không có thời gian để sửa từng cái một" –

+0

Tôi biết, đó không phải mã của tôi. Tôi chưa bao giờ làm thế. Tuy nhiên, tôi muốn biết tại sao nó không hoạt động trên một máy chủ và nó hoạt động trên máy chủ khác. –

Trả lời

8

http://php.net/manual/en/pdo.prepare.php trạng thái:

Bạn phải bao gồm một marker tham số duy nhất cho mỗi giá trị mà bạn muốn vượt qua để báo cáo kết quả khi bạn gọi PDOStatement :: thực hiện().Bạn không thể sử dụng dấu tham số được đặt tên có cùng tên nhiều hơn một lần trong câu lệnh đã chuẩn bị, trừ khi chế độ mô phỏng được bật.

Vì đây cho thấy, nguyên nhân có khả năng đằng sau mã của bạn làm việc trên một máy chủ và không khác là PDO::ATTR_EMULATE_PREPARES bị vô hiệu hóa trên máy chủ mà mã không thành công trên. Như tài liệu nói, thuộc tính này có hiệu quả loại bỏ các hạn chế ngăn cản bạn sử dụng một dấu tham số cùng tên hai lần (cùng với một số hạn chế khác).

+0

cũng .. không phải là một câu trả lời, thực sự :) nhưng cảm ơn –

+0

Đó là một câu trả lời một phần: P Tôi sẽ cập nhật nó nếu tôi tìm thấy bất cứ điều gì nhiều hơn, nhưng tôi nhận được hư không vào lúc này. Không thể thấy lý do tại sao nó nên làm việc, phải trung thực. – Hecksa

+0

cũng .. tại sao không? Nếu bạn thử cập nhật thô trên bảng điều khiển mysql trên bảng thử nghiệm nó hoạt động (ví dụ 1). Vấn đề chỉ xảy ra nếu bạn thay thế các giá trị bằng phần giữ chỗ. –

-1
try { 
    $db = new PDO('mysql:host=localhost;dbname=vendor_management_system', 'root', ''); 
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 
}catch(PDOException $e) { 
    echo 'ERROR: ' . $e->getMessage(); 
} 




$fields[] = 'car_name'; 
$fields[] = 'model_no'; 
$fields[] = 'maker_id'; 
$fields[] = 'dealer_id'; 

$values[] = "testcar"; 
$values[] = "no#1"; 
$values[] = 2; 
$values[] = 4; 



echo SQLUpdate('car_details', $fields, $values,'car_id = 32 and car_name = "testname"',$db); 




//START: SQLUpdate 
//$fields = array of fields in DB 
//$values = array of values respective to the $fields 
function SQLUpdate($table,$fields,$values,$where,$db) { 



    //build the field to value correlation 
    $buildSQL = ''; 
    if (is_array($fields)) { 

     //loop through all the fields and assign them to the correlating $values 
     foreach($fields as $key => $field) : 
     if ($key == 0) { 
      //first item 
      $buildSQL .= $field.' = ?'; 
      } else { 
      //every other item follows with a "," 
      $buildSQL .= ', '.$field.' = ?'; 
      } 
    endforeach; 

    } else { 
    //we are only updating one field 
     $buildSQL .= $fields.' = :value'; 
    } 

    $prepareUpdate = $db->prepare('UPDATE '.$table.' SET '.$buildSQL.' 
WHERE '.$where); 

    //execute the update for one or many values 
    if (is_array($values)) { 
    $affected_rows=$prepareUpdate->execute($values); 
    return $affected_rows; 
    } else { 
    $affected_rows=$prepareUpdate->execute(array(':value' => $values)); 
    return $affected_rows; 
    } 


    //record and print any DB error that may be given 
    $error = $prepareUpdate->errorInfo(); 
    if ($error[1]) print_r($error); 

} 
//END: SQLUpdate 
+0

Bạn có thể giải thích câu trả lời của bạn thêm vào câu hỏi này hay mã của bạn làm gì? – Kermit

-2
$maker_id=1; 
$stmt = $db->prepare("UPDATE car_details SET maker_id=?"); 
$affected_rows=$stmt->execute(array($maker_id)); 
echo $affected_rows.' were affected'; 
+2

Bạn có thể giải thích câu trả lời của bạn thêm vào câu hỏi này hay mã của bạn làm gì? – Kermit

Các vấn đề liên quan