【问题标题】:MySQL update using PDO and prepared statement not workingMySQL 使用 PDO 更新和准备好的语句不起作用
【发布时间】:2012-03-01 20:29:21
【问题描述】:

我在使用 php PDO 和 mysql 时遇到了一个奇怪的问题。

我有下表:

create table test_table ( id integer, value text );

单行:

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

当我尝试使用准备好的语句更新这一行时,根据我使用的语法,我得到了不同的行为:

// 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);

在第三种情况下,在我的服务器上,没有对行执行更新,没有任何原因,也没有异常/错误。在另一台服务器上它可以工作。我不是在寻找类似的答案:“所以?使用第一个或第二个实现”:)

我在问为什么第三个实现不起作用,因为我正在将大量代码从服务器迁移到另一台(这不是我的代码),它包含很多查询像这个,我没有时间一一修复。在当前服务器上可以正常工作,而在新服务器上则不行。

为什么第三个实现不起作用? php/pdo/mysql 是否有任何可能影响此行为的配置?

谢谢。

更新: 试图挤出错误信息:

$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);

在两台服务器上执行此代码(工作和不工作):

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

更新 2

看看这个进一步的测试:

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)
);

难以置信,不是吗?我现在怀疑存在一些专门针对 PDO+占位符处理的每个表的 第一列 的特殊更新行为。

【问题讨论】:

  • 您正在使用 :id 来更改 'id' 的值以及识别行。你确定这是你想做的吗?
  • @middus:正如他所说:“我正在将大量代码从服务器迁移到另一台(不是我的代码),它包含很多像这样的查询,我没有时间一个一个地修复它们”
  • 我知道,这不是我的代码。我永远不会那样做。不过,我想知道为什么它不能在服务器上运行而在另一个服务器上运行。
  • 服务器之间还有什么其他的不同点吗?也许一个数据库有一个关于 id 的索引而一个没有,或者你能想到的任何其他东西?正如你所说,给定这些版本,mysql 版本似乎不可行。

标签: php mysql pdo


【解决方案1】:

http://php.net/manual/en/pdo.prepare.php 状态:

您必须为希望添加的每个值添加一个唯一的参数标记 调用 PDOStatement::execute() 时传入语句。 你 不能多次使用同名的命名参数标记 准备好的语句,除非仿真模式开启。

正如这表明的那样,您的代码在一台服务器而不是另一台服务器上运行的可能原因是 PDO::ATTR_EMULATE_PREPARES 在代码失败的服务器上被禁用。正如文档所说,此属性有效地消除了阻止您使用相同名称的参数标记两次的限制(以及其他一些限制)。

【讨论】:

  • 这是一个部分答案:P 如果我想出更多信息,我会更新它,但我目前无处可去。老实说,看不出它为什么会起作用。
  • 好吧.. 为什么不呢?如果您在测试表上尝试在 mysql 控制台上进行原始更新,它可以工作(示例 1)。仅当您将值替换为占位符时才会出现问题。
  • 正如答案中所解释的 - 导致问题的是使用 PDO。不允许将 :id 两次放入查询中,如果您想在查询中两次放入相同的值,则需要使用另一个名称不同的参数(尽管包含相同的值)。
  • 例如,update test_table set id=:id, value=:value where id=:idCopy 就可以了。
  • 是的,这行得通,忘记我删除的评论。这是一个占位符问题。但仍然最初的问题旨在了解它如何工作..那个 PDO 版本的错误?
【解决方案2】:
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

【讨论】:

  • 您能否解释一下您的回答对这个问题有何补充或您的代码做了什么?
【解决方案3】:
$maker_id=1;
$stmt = $db->prepare("UPDATE car_details SET maker_id=?");
$affected_rows=$stmt->execute(array($maker_id));
echo $affected_rows.' were affected';

【讨论】:

  • 你能解释一下你的答案对这个问题有什么作用或者你的代码做了什么吗?
【解决方案4】:

面临同样的问题

with update 语句(插入和选择与数组集一起工作)

我发现通过绑定参数执行:

$qry = $bd->prepare("UPDATE users SET name = :name WHERE id = :id");
$qry->bindParam(':name','user1');          
$qry->bindParam(':id','1');   
$qry->execute();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 2018-01-24
    • 2011-08-01
    • 2011-11-10
    • 1970-01-01
    相关资源
    最近更新 更多