Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
准备好的语句不能通过php在整个事务中使用吗?_Php_Postgresql_Transactions_Pdo_Prepared Statement - Fatal编程技术网

准备好的语句不能通过php在整个事务中使用吗?

准备好的语句不能通过php在整个事务中使用吗?,php,postgresql,transactions,pdo,prepared-statement,Php,Postgresql,Transactions,Pdo,Prepared Statement,我在一个LAPP环境(linux apache postgresql php)上工作,我只是想了解如何在事务中使用准备好的语句(如果可能的话) 我希望代码比文字解释得更好: 示例1,简单事务: BEGIN; INSERT INTO requests (user_id, description, date) VALUES ('4', 'This dont worth anything', NOW()); UPDATE users SET num_requests = (num_requests +

我在一个LAPP环境(linux apache postgresql php)上工作,我只是想了解如何在事务中使用准备好的语句(如果可能的话)

我希望代码比文字解释得更好:

示例1,简单事务:

BEGIN;
INSERT INTO requests (user_id, description, date) VALUES ('4', 'This dont worth anything', NOW());
UPDATE users SET num_requests = (num_requests + 1) WHERE id = '4';
--something gone wrong, cancel the transaction
ROLLBACK;
UPDATE users SET last_activity = NOW() WHERE id = '4'
COMMIT;
在上面的例子中,如果我正确地取消了事务,数据库中唯一的影响将是最后一个_活动的更新。。。是吗

如果我尝试在php中使用该事务(使用PDO或pg_u方法),代码应该如下所示(示例2):

这很好。也许丑陋难看,但似乎有效(建议总是受欢迎的)

无论如何,当我试图用准备好的语句来解释示例2时,我的问题就出现了(我知道在示例2中,使用准备好的语句不是很有用)

例3:

/* skip the connection */
pg_prepare($pgConnection, 'insert_try', "INSERT INTO requests (user_id, description, date) VALUES ('$1', '$2', $3)");
pg_query($pgConnection, "BEGIN");
pg_execute($pgConnection, 'insert_try', array($user_id, 'This dont worth anything', date("Y-m-d")));
/* and so on ...*/
好的,示例3根本不起作用,如果事务在回滚中到期,那么准备好的语句将有效

那么,准备好的报表不能用于交易,还是我走错了路

编辑:

在尝试了一些PDO之后,我达到了这一点:

<?php
$dbh = new PDO('pgsql:host=127.0.0.1;dbname=test', 'myuser', 'xxxxxx');

$rollback = false;

$dbh->beginTransaction();

//create the prepared statements
$insert_order = $dbh->prepare('INSERT INTO h_orders (id, id_customer, date, code) VALUES (?, ?, ?, ?)');
$insert_items = $dbh->prepare('INSERT INTO h_items (id, id_order, descr, price) VALUES (?, ?, ?, ?)');
$delete_order = $dbh->prepare('DELETE FROM p_orders WHERE id = ?');

//move the orders from p_orders to h_orders (history)
$qeOrders = $dbh->query("SELECT id, id_customer, date, code FROM p_orders LIMIT 1");
while($rayOrder = $qeOrders->fetch(PDO::FETCH_ASSOC)){
    //h_orders already contain a row with id 293
    //lets make the query fail
    $insert_order->execute(array('293', $rayOrder['id_customer'], $rayOrder['date'], $rayOrder['code'])) OR var_dump($dbh->errorInfo());
    //this is the real execute
    //$insert_order->execute(array($rayOrder['id'], $rayOrder['id_customer'], $rayOrder['date'], $rayOrder['code'])) OR die(damnIt('insert_order'));
    //for each order, i move the items too
    $qeItems = $dbh->query("SELECT id, id_order, descr, price FROM p_items WHERE id_order = '" . $rayOrder['id'] . "'") OR var_dump($dbh->errorInfo());
    while($rayItem = $qeItems->fetch(PDO::FETCH_ASSOC)){
        $insert_items->execute(array($rayItem['id'], $rayItem['id_order'], $rayItem['descr'], $rayItem['price'])) OR var_dump($dbh->errorInfo());
    }
    //if everything is ok, delete the order from p_orders
    $delete_order->execute(array($rayOrder['id'])) OR var_dump($dbh->errorInfo());
}
//in here i'll use a bool var to see if anythings gone wrong and i need to rollback,
//or all good and commit
$dbh->rollBack();
//$dbh->commit();
?>
您应该使用

pdo_obj->beginTransaction()
pdo_obj->commit()
pdo_obj->prepare()
在第一个示例的末尾还有一个随机提交

begin
// do all your stuff
// check for errors through interface
commit OR not

pg_query($pgConnection, "ROLLBACK"); // end of tx(1)
// start new transaction after last rollback = tx(2)
pg_query($pgConnection, "UPDATE users SET last_activity = NOW() WHERE id = '$id_user'");
// commit tx(2) or don't here
// this isn't needed pg_query($pgConnection, "COMMIT");
如果您没有提交,并且需要手动调整内容,请使用另一个事务。准备查询(如果我记得的话)是事务的一部分,因为它可能会失败。您不能仅仅手动地获取SQL语句并将其转换为查询。PDO接口具有抽象是有原因的。:)


对于PostgreSQL,如果任何语句在事务期间产生服务器错误,则该事务将标记为中止。这并不意味着它实际上已经回滚了——只是你除了回滚之外几乎什么都做不了。我假设PDO不会自动发出回滚,它会等待您调用“回滚”方法

要实现我认为您想要的,您可以使用保存点。您不必回滚整个事务,只需回滚到保存点并继续事务即可。我将给出一个使用psql的示例:

srh@srh@[local] =# begin;
BEGIN
srh@srh@[local] *=# insert into t values(9,6,1,true);
INSERT 0 1
srh@srh@[local] *=# savepoint xyzzy;
SAVEPOINT
srh@srh@[local] *=# insert into t values(9,6,2,true);
ERROR:  duplicate key value violates unique constraint "t_pkey"
srh@srh@[local] !=# insert into t values(10,6,2,true);
ERROR:  current transaction is aborted, commands ignored until end of transaction block
srh@srh@[local] !=# rollback to savepoint xyzzy;
ROLLBACK
srh@srh@[local] *=# insert into t values(10,6,2,true);
INSERT 0 1
srh@srh@[local] *=# commit;
COMMIT
srh@srh@[local] =# 
所以在这个例子中,t的第一列是主键。我试图在t中插入两行id为9的行,结果得到了唯一性约束。我不能用正确的值重做insert,因为现在任何语句都会出现“当前事务已中止…”错误。但是我可以做“回滚到保存点”,这会让我回到我做“保存点”时的状态(“xyzy”是保存点的名称)。然后我可以发出正确的insert命令并最终提交事务(提交两个插入)

因此,在您的情况下,我怀疑您需要做的是在UPDATE语句之前创建一个保存点:如果出现错误,请执行“回滚到保存点”并设置您的标志。您需要为保存点生成唯一的名称:例如,使用计数器


我不完全明白你为什么要这么做。一旦知道要回滚事务,您肯定要停止处理吗?或者循环中还有其他必须进行的处理吗?

我不认为准备查询是事务的一部分——如果我手动执行“开始”、“将测试准备为选择版本()”、“中止”、“执行测试”,则返回的是版本字符串。话虽如此,如果准备查询失败,您的事务将被标记为已中止,因此它们在这方面与事务相关。我仍然会在事务中进行准备。使编码更简单,以捕获异常以及与事务相关的逻辑代码块中没有的异常。当您有许多查询时,它也会有所帮助,将它们准备在几乎“父母”的范围内,让它们作为读者处理该事务。如果准备好的语句在多个地方使用,这是不同的。执行准备好的语句当然应该在事务内部工作,就像执行常规语句一样。我一直在使用它们,但是是从Perl,而不是PHP。如果在您没有预料到的情况下进行了提交,那么可能会出现跟踪服务器上实际执行的内容(set log_statement='all')?我认为问题可能更多地归因于PDO的不当使用。API使用该库进行更深入的反馈,使查看失败的内容、原因、地点和时间变得更简单。在p_orders示例中,我尝试做的是将所有p_orders和p_项目移动到h_orders和h_items表中,如果出现故障,则全部结束。在现实世界中,我可能会对每个p_订单使用一个事务,但这只是一个示例来帮助我如何使用事务stmt environmanet..该死的-PDO不支持嵌套保存点--好吧,我尝试了通过shell实现的解决方案,它是有效的,我只需要在循环开始之前添加保存点。。谢谢,我将四处寻找一个更好的php数据库处理程序(条令?)
srh@srh@[local] =# begin;
BEGIN
srh@srh@[local] *=# insert into t values(9,6,1,true);
INSERT 0 1
srh@srh@[local] *=# savepoint xyzzy;
SAVEPOINT
srh@srh@[local] *=# insert into t values(9,6,2,true);
ERROR:  duplicate key value violates unique constraint "t_pkey"
srh@srh@[local] !=# insert into t values(10,6,2,true);
ERROR:  current transaction is aborted, commands ignored until end of transaction block
srh@srh@[local] !=# rollback to savepoint xyzzy;
ROLLBACK
srh@srh@[local] *=# insert into t values(10,6,2,true);
INSERT 0 1
srh@srh@[local] *=# commit;
COMMIT
srh@srh@[local] =#