【问题标题】:PDOs' rule with UPDATE and FETCHALL()带有 UPDATE 和 FETCHALL() 的 PDO 规则
【发布时间】:2015-07-20 14:52:31
【问题描述】:

在我的 SQL 查询中,我有一个 INSERT、UPDATE 和一个 SELECT 查询全部在一个查询中,如下面的查询

INSERT INTO questions (user_mail, question_id, question, username, created_at) VALUES (:fid, :qid, :com, :pid, :dat);
UPDATE users SET  activity = activity + 1 WHERE face_id = :fid;
SELECT questions.face_id
       FROM  questions
       WHERE questions.question_id = :qid

我在一个 PDO 查询中拥有所有这三个查询,但是有一个奇怪的规则使用 UPDATE 查询和 $result = $stmt->fetchAll(); 任何关于如何解决这个问题的想法,因为我的 PDO 不断吐出一个错误,上面写着

SQLSTATE[HY000]:一般错误

这是组合查询的结果;并且请它强制我结合上面的查询,否则我将不得不更改我的整个代码逻辑,其次我已经使用$result = $stmt->execute ( $params ); 来执行查询,但它从我需要的SELECT 查询部分返回值使用$stmt->fetchAll();。还有其他方法吗?

另一种方式导致另一个问题

在其他无缓冲查询仍处于活动状态时无法执行查询

case PUT_COMMENTS :
            $this->querymultiple ['insert'] = "INSERT INTO talks (face_id, comment, phone_id, created_at) VALUES (:fid, :com, :pid, :dat);";

            $this->querymultiple ['update'] = "UPDATE facelog SET  activity = activity + 1 WHERE face_id = :fid;
                                               UPDATE facelog SET  commentCount = commentCount + 1 WHERE face_id = :fid;";

            $this->querymultiple ['select'] = "SELECT
                                                talks.comment,
                                                talks.face_id,
                                                userlog.gcm_id
                                               FROM
                                                    talks,
                                                    tagged,
                                                    userlog
                                               WHERE
                                                   talks.face_id = :fid
                                                   AND talks.comment = :com
                                                   AND tagged.face_id = talks.face_id
                                                   AND userlog.phone_id = tagged.phone_id";

            $this->params ['insert'] = array (
                    ':' . FACE_ID => $value [FACE_ID],
                    ':' . COMMENT => $value [COMMENT],
                    ':' . DATE => $value [DATE],
                    ':' . PHONE_ID => $value [PHONE_ID] 
            );

            $this->params ['update'] = array (
                    ':' . FACE_ID => $value [FACE_ID] 
            );

            $this->params ['select'] = array (
                    ':' . FACE_ID => $value [FACE_ID],
                    ':' . COMMENT => $value [COMMENT] 
            );

            $this->pdo_query->RunMultipleQuery ( $tag, $this->querymultiple, $this->params, SELECT );
            break;

我的RunMultipleQuery()方法如下

/**
 * This method runs multiple the Queries
 *
 * @param unknown $tag          
 * @param unknown $query            
 * @param unknown $params           
 * @param unknown $query_type           
 */
public function RunMultipleQuery($tag, $query, $params, $query_type) {
    try {
        $stmt = array ();
        $result = array ();
        if (! empty ( $query ) || ! empty ( $params )) {
            $this->pdo_db->pdo_db->beginTransaction ();
            $stmt ['insert'] = $this->pdo_db->pdo_db->prepare ( $query ['insert'] );
            $stmt ['update'] = $this->pdo_db->pdo_db->prepare ( $query ['update'] );
            $stmt ['select'] = $this->pdo_db->pdo_db->prepare ( $query ['select'] );

            $result ['insert'] = $stmt ['insert']->execute ( $params ['insert'] );
            $result ['update'] = $stmt ['update']->execute ( $params ['update'] );
            $result ['select'] = $stmt ['select']->execute ( $params ['select'] );

            $stmt ['insert']->closeCursor ();
            $stmt ['update']->closeCursor ();
            $stmt ['select']->closeCursor ();

            $this->pdo_db->pdo_db->commit ();
        } else {
            $result = null;
        }
    } catch ( PDOException $e ) {
        // For testing, you could use a die and message.
        // die("Failed to run query: " . $ex->getMessage());

        // or just use this use this one to product JSON data:
        // $response["message"] = '0:'.$ex->getMessage() ;
        // die(json_encode($response["message"]));
        $error_message = $e->getMessage ();
        $error_code = $e->getCode ();
        $error_trace = $e->getTrace ();
        Log::LogError ( $error_message, $error_code, $error_trace );
        // roll back transaction
        if ($this->pdo_db->pdo_db->inTransaction ()) {
            $this->pdo_db->pdo_db->rollBack ();
        }
        $result = null;
    }

    if ($query_type == SELECT) {
        // echo 'result = '.$result;
        try {
            if (! empty ( $result ['select'] )) {
                // fetching all the rows from the query
                SendtoClient::Toclient ( $tag, $stmt ['select']->fetchAll () );
            } else {
                SendtoClient::Toclient ( $tag, null );
            }
        } catch ( PDOException $e ) {
            $error_message = $e->getMessage ();
            $error_code = $e->getCode ();
            $error_trace = $e->getTrace ();
            Log::LogError ( $error_message, $error_code, $error_trace );
        }
    }
}

【问题讨论】:

  • 您的选择查询末尾没有分号,而且,您看过这篇文章吗? Multiple queries in PDO statement
  • 我真的看不出为什么必须一起发送所有 3 个查询,也没有理由完全更改代码逻辑。这是您正在使用的愚蠢解决方案。只需启动一个事务,一个一个地发出所有查询,然后提交。从您的 POV 来看,加起来可能少于 50 个字符,但与您的示例不同 - 它会起作用。
  • 是的,我看过@Osuwariboy 的帖子,但它并没有解决我的问题,我如何在没有$stmt->fetchAll(); 或`$stmt->fetch();`的情况下获取我选择的值跨度>
  • @N.B.我对您使用的“愚蠢”一词有点生气,但请在下面发布您的解决方案作为答案。
  • 愚蠢这个词不是用来反映你的属性的。使用愚蠢这个词是因为解决方案很糟糕,这与你的技能、智商、能力或任何东西无关。我发表这样的评论只是为了反映这种解决方案在可能的解决方案中的价值——而且这种解决方案根本不好。如果你被愚蠢这个词冒犯了,那么我很抱歉,选择的解决方案很糟糕。我会发布一个答案来描述我的想法。

标签: php mysql pdo


【解决方案1】:

您应该做的是将您的查询隔离在事务中并一一发出。我将发布一个示例,您如何使用准备好的语句来做到这一点:

try
{

    $pdo->beginTransaction();

    $stmt['insert'] = $pdo->prepare("INSERT INTO questions (user_mail, question_id, question, username, created_at) VALUES (:fid, :qid, :com, :pid, :dat)");
    $stmt['update'] = $pdo->prepare("UPDATE users SET  activity = activity + 1 WHERE face_id = :fid");
    $stmt['select'] = $pdo->prepare("SELECT questions.face_id FROM  questions WHERE questions.question_id = :qid");

    $stmt['insert']->execute([':fid' => 'your value', ':qid' => 'your value', ':com' => 'your value', ':pid' => 'your value', ':dat' => 'your value']);
    $stmt['update']->execute([':fid' => 'your value']);
    $stmt['select']->execute([':qid' => 'your qid']);

    $rows = $stmt['select']->fetchAll();

    $pdo->commit();
}
catch(\PDOException $e)
{
    echo "Something went terribly wrong: " . $e->getMessage();

    if($pdo->inTransaction())
    {
        $pdo->rollBack();
    }
}

您不应该在单个 PDO 函数中发送代表 3 个查询的字符串的原因是:它不起作用。 第二个原因是:很难调试或维护类似的东西。对每种类型的工作进行查询要干净得多。 第三个原因:假设这三个查询可以一起工作,你怎么知道哪一个失败了?

使用准备好的语句可以很好地控制这个流程。使用事务可确保一切按计划进行 - 如果在此过程中出现问题,您的数据库不会因孤立数据而损坏。最好的部分 - 您可以捕获异常并检查其错误消息以查看哪个查询出错。

我发布了一个代码示例,您应该使用您计划发送到数据库的值对其进行修改。从性能 POV 来看,它稍微慢一些(除非您发出大量查询,在这种情况下它非常快)。

【讨论】:

  • 这真是太好了!感谢您为我清理玉米棒网,了解我将如何做到这一点。会立即尝试您的解决方案,但我认为它已经奏效了。 ;)
  • 没问题,我很高兴事情变得更清楚了,即使有点:)
  • 我刚刚完成了你的代码的实现,但是我收到了另一种错误,上面写着cannot execute query while other unbuffered queries are still active
  • 在您$stmt->execute() 之后,在该声明中使用$stmt->closeCursor()。然后执行下一个。但是男孩,你有没有让你的代码变得复杂......如果我是你,我会保持它非常简单。
猜你喜欢
  • 2020-08-08
  • 2017-06-16
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-20
  • 2011-02-15
相关资源
最近更新 更多