【问题标题】:How can I use prepared statements combined with Transactions with PHP?如何将准备好的语句与 Transactions with PHP 结合使用?
【发布时间】:2018-01-30 07:43:47
【问题描述】:

我的目标是同时使用事务和准备好的语句,以实现数据的完整性和防止 SQL 注入。

我有这个:

   try {
        $cnx = new PDO($dsn,$dbuser,$dbpass);   
        $cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        $cnx->beginTransaction();
        $cnx->query("SELECT * FROM users WHERE username=$escaped_input");
        $cnx->query("SELECT * FROM othertable WHERE some_column=$escaped_input_2");

        $cnx->commit();
    }

    catch (Exception $e){
           $cxn->rollback();
           echo "an error has occured";

    }

我想将查询与准备好的语句合并:

$stmt=$cxn->prepare("SELECT * FROM users WHERE username=?");
$stmt->execute(array($user_input));

$stmt_2=$cxn->prepare("SELECT * FROM othertable WHERE some_column=?");
$stmt_2->execute(array($user_input_2));

我怎样才能做到这一点?

编辑

我收到此错误:

PHP 解析错误:语法错误,意外的 T_CATCH

这是我更新的代码:

try 
{
    $cnx = new PDO($dsn,$dbuser,$dbpass);   
    $cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $cnx->beginTransaction();
    $stmt=$cnx->prepare("SELECT * FROM users WHERE username=?");
    $stmt->execute(array($username));

    $cnx->commit();

    while ($row=$stmt->fetch(PDO::FETCH_OBJ)){
    echo $stmt->userid;

}

catch(Exception $e) { 
    if (isset($cnx)) 
        $cnx->rollback();
       echo "Error:  " . $e; 
    }

【问题讨论】:

  • 你能重述这个问题吗?
  • 不,因为我不知道如何处理commit()execute(),因为它们应该做大致相同的事情
  • 不,“提交”和“执行”不要“做大致相同的事情”;)
  • 我期待这个回复,我正在要求它.. :) commit 有什么作用?我认为它完全提交/执行了所有查询
  • 你在最后的 WHILE 语句中缺少一个右括号

标签: php mysql pdo


【解决方案1】:

在调用“beginTransaction”之后调用“execute”。

你在哪里称呼“准备”并不重要。

这是一个完整的例子:

http://php.net/manual/en/pdo.begintransaction.php

示例:

 try {
    $cnx = new PDO($dsn,$dbuser,$dbpass);   
    $cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $cnx->beginTransaction();

    $stmt=$cxn->prepare("SELECT * FROM users WHERE username=?");
    $stmt->execute(array($user_input));

    $stmt_2=$cxn->prepare("SELECT * FROM othertable WHERE some_column=?");
    $stmt_2->execute(array($user_input_2));

    $cnx->commit();
  }
  catch (Exception $e){
    $cxn->rollback();
    echo "an error has occurred";
  }

PS: 1) 当然,我假设 $user_input 和 $user_input_2 可以立即使用。您不希望您的交易在不必要的时间内挂起;)

2)根据您上面的评论回复,我认为您可能会混淆“执行”和“开始传输/提交”。请看我的链接。

3) 你甚至需要一笔交易吗?你只是在做两个“选择”。

4) 最后,为什么不做一个“加入”(或联合,如果兼容)而不是两个“选择”?

【讨论】:

  • 我建议加入我的答案,我认为这就是他所说的“合并为一个”的意思
【解决方案2】:
try 
{
    $cnx = new PDO ($dsn,$dbuser,$dbpass);   
    $cnx->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $cnx->beginTransaction ();

    $stmt = $cnx->prepare ("SELECT * FROM users WHERE username=?");
    $stmt->execute(array($username));

    $cnx->commit();

    while ($row = $stmt->fetch (PDO::FETCH_OBJ)){
        echo $row->userid;
    }
}

catch (Exception $e) { 
    if (isset ($cnx)) 
        $cnx->rollback ();
       echo "Error:  " . $e; 
    }
}

【讨论】:

  • 这个,虽然少了一点
  • 1) 如果 PDO 构造函数抛出异常,catch 块将引起关于未定义变量的通知。 2)完全吞下错误信息不是一个好主意。在现实世界中,应该记录实际的消息和堆栈跟踪。
  • 异常处理我都没看,但是DCoder是绝对正确的,应该也改进一下
  • 是的,但提出的问题与错误处理无关,因此您的回答是可以接受的
  • 它远非完美,但我已经稍微改进了异常处理:)
【解决方案3】:

你是这个意思吗?

try {
    $cnx = new PDO($dsn,$dbuser,$dbpass);   
    $cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $cnx->beginTransaction();
    $stmt=$cnx->prepare("
        SELECT * FROM users, othertable 
        WHERE users.username=? 
        AND othertable.some_column=?");

    $stmt->execute(array($user_input,$user_input_2));

    $cnx->commit();
}
catch (Exception $e){
       $cnx->rollback();
       echo "an error has occured";
}

这是假设两个表数据没有重复的字段名称,否则你将不得不使用:

SELECT users.field1 as u_field1, othertable.field1 as o_field1 FROM users, othertable 
WHERE users.username=? 
AND othertable.some_column=?

【讨论】:

  • 您好,感谢您的回复。我实际上以两个 SELECT 查询为例,但我也想使用 UPDATE 查询。谢谢,问候
  • dev.mysql.com/doc/refman/5.0/en/join.html 有使用连接进行 UPDATE / DELETE / SELECT 查询的示例
猜你喜欢
  • 2010-10-14
  • 1970-01-01
  • 2022-01-06
  • 2019-04-07
  • 2015-06-27
  • 1970-01-01
  • 2016-12-17
  • 1970-01-01
  • 2016-07-22
相关资源
最近更新 更多