Ich arbeite an einer LAPP-Umgebung (Linux Apache Postgresql PHP), und ich bin nur Triyn, um herauszufinden, wie Sie die vorbereitete Anweisung innerhalb der Transaktion (wenn möglich) verwenden.Kann die vorbereitete Anweisung durch die Transaktion von PHP verwendet werden?
I-Code hoffentlich besser erklären, dann Worte:
Beispiel 1, einfache Transaktion:
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;
In dem obigen Beispiel, wenn ich Recht, die Transaktion undestood, wird der einzige Effekt in der Datenbank sein das Update von last_activity ... ye?
Wenn ich versuche, diese Transaktion in PHP zu verwenden (beide mit gU oder pg_ Methoden) sollte der Code aussieht, dass (Beispiel 2):
/* skip the connection */
pg_query($pgConnection, "BEGIN");
pg_query($pgConnection, "INSERT INTO requests (user_id, description, date) VALUES ('$id_user', 'This dont worth anything', NOW())");
pg_query($pgConnection, "UPDATE users SET num_requests = (num_requests + 1) WHERE id = '$id_user'");
//something gone wrong, cancel the transaction
pg_query($pgConnection, "ROLLBACK");
pg_query($pgConnection, "UPDATE users SET last_activity = NOW() WHERE id = '$id_user'");
pg_query($pgConnection, "COMMIT");
Und das funktioniert gut. Vielleicht hässlich zu sehen, aber scheinen (Vorschlag immer willkommen ist) zu arbeiten
Wie auch immer, mein Problem kommen, wenn ich versuche, das Beispiel 2 mit den vorbereiteten Anweisungen zu envolve (ich weiß, dass in dem Beispiel 2 die Verwendung vorbereitet Aussagen nicht sehr nützlich ist)
Beispiel 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 ...*/
Nun, das Beispiel 3 einfach nicht funktioniert, wird die vorbereitete Anweisung, wenn die Transaktion fällig Rollbacks wirksam sein.
So können die vorbereiteten Anweisungen nicht in der Transaktion verwendet werden, oder nehme ich den falschen Weg?
EDIT:
Nach einigen Versuchen mit PDO, ich an diesem Punkt angekommen bin:
<?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();
?>
Der Code nicht oben mit diesem Ausgang:
array(3) { [0]=> string(5) "00000" [1]=> int(7) [2]=> string(62) "ERROR: duplicate key violates unique constraint "id_h_orders"" }
array(3) { [0]=> string(5) "25P02" [1]=> int(7) [2]=> string(87) "ERROR: current transaction is aborted, commands ignored until end of transaction block" }
Fatal error: Call to a member function fetch() on a non-object in /srv/www/test-db/test-db-pgsql-08.php on line 23
So, Wenn die erste Ausführung fehlschlägt (die mit ID 293), wird die Transaktion automatisch abgebrochen ... macht das PDO automatisches Rollback oder etwas anderes?
Mein Ziel ist es, die erste große while-Schleife zu beenden, und am Ende, mit einem bool var als Flag, entscheiden, ob Rollback oder Commit die Transaktion.
Die Ausführung vorbereiteter Anweisungen sollte in Transaktionen genauso funktionieren wie die Ausführung regulärer Anweisungen. Ich benutze sie die ganze Zeit, aber von Perl, nicht PHP. Vielleicht wird die Verfolgung, was tatsächlich auf dem Server ausgeführt wird (set log_statement = 'all'), angezeigt, wenn Commits ausgeführt werden, wenn Sie sie nicht erwartet haben? – araqnid
Ich denke, dass das Problem mehr auf falsche Verwendung von PDO zurückzuführen ist. Die API verwendet die Bibliothek für tiefere Rückmeldungen und macht es einfacher zu sehen, was fehlschlägt, warum, wo und wann. –
Nur editet, danke – Strae