How to Trap Errors in a PHP MySQL Transaction with Rollback - php

I have a transaction that does an insert into several tables. I want to catch any errors so that if any of the inserts fail they will all be rolled back. Here is a short version of what I am trying to do:
try {
$this->conn->beginTransaction();
//build an sql insert...
$sql = "INSERT INTO...
$stmt = $this->conn->prepare($sql);
$stmt->execute();
//do more inserts...
//commit the transaction
$this->conn->commit();
$this->message = 'The Program has been added.';
//catch errors and rollback
} catch (PDOException $e) {
$this->message = $e->getMessage();
$this->conn->rollBack();
}
All of the inserts work properly but if there is a problem, I don't seem to be catching the error and the rollback does not happen. For instance, if I write bad sql or don't pass values for parameters, I just get php errors but the inserts proceed anyway. I can post the full code if it helps but maybe it is something obvious?

Related

RollBack () and beginTransaction() not work in my PHP PDO

RollBack () and beginTransaction() not work in my PHP PDO and my table type is innoDB. In the following code my $sql1 is correct and my $sql2 is wrong (I added d to $last_id to just make it wrong). But it still executes sql1 meaning roll back no effect. Thank you for your advice.
<?php
include 'connect.php';
// Get multiple input field's value
try {
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Starts our transaction
$conn->beginTransaction();
foreach ($_POST['phone'] as $value) {
$sql1 = "INSERT INTO tbl_contact_info (type)
VALUES ('$value')";
// use exec() because no results are returned
$conn->exec($sql1);
$last_id = $conn->lastInsertId();
$sql2="INSERT INTO tbl_img (img_type)
VALUES ('$dlast_id')";
$conn->exec($sql2);
}
// Commits out queries
$conn->commit();
echo "New record created successfully";
}
catch(PDOException $e)
{
// Something borked, undo the queries!!
$conn->rollBack();
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
?>
First of all (and sorry it it's obvious but I realised it's not always clear to everyone) SQL and PHP are different languages. MySQL Server will not react to Undefined variable notices triggered in PHP code.
Secondly, notices are not exceptions so they cannot be caught with try/catch statements. (You can certainly write a custom error handler that will throw exceptions on errors but it doesn't seem to be the case here.)

Unexpected results in PDO Transactions

My problem is kinda simple or it maybe a silly mistake from my side. But I don't know I am just getting unexpected results while using PDO in php.
Code goes like this,
try
{
$_pdo = get_pdo_instance();
$_pdo->beginTransaction();
//query 1
$_pdo->query("some query"); // I have error in query 3 but this query 1 is still executed.
//query 2
$_pdo->query("some query"); // only executes when there are no errors.
//query 3
$_pdo->query("some wrong query"); // let's say I have an error in this sql
$_pdo->commit();
}
catch(Exception $ex)
{
$_pdo->rollback();
}
I am explaining the problem now,
In given example I have some sql error in query 3, so none the queries should run as they all belongs to single transaction.
But in my case query 1 always run even if there are errors in that try block.
Maybe its something simple but I have no idea why this is happening.
Edit:
Function definition,
function get_pdo_instance()
{
try
{
$conn = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
die('ERROR: ' . $e->getMessage());
}
return $conn;
}
Exceptions are used only for PHP errors. In the code above, you're trying to catch a MySQL error. When PHP reads your try block, everything looks fine, and it therefore has no exception to catch.
You can do error checking with PDO and MySQL like:
if(!$_pdo->query("some query")) {
// Do something
}
See the documentation for PDO Error Handling. You need to turn exception raising on.
try {
$_pdo = get_pdo_instance();
$_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$_pdo->beginTransaction();
$_pdo->query("some query");
$_pdo->query("some query");
$_pdo->query("some wrong query");
$_pdo->commit();
}
catch(Exception $ex) {
$_pdo->rollback();
}
Here is my solution,
I was catching Exception, instead in this case I had to do catch PDOException.
I guess that solved my problem, but I haven't tested this thing completely. I will post updates if any.

PHP - PDO Transaction sequence

In my MySQL database very rarely I get duplicate rows. I'm just looking at my code and I want to check if my transaction code is causing this problem. Here is it:
try
{
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$con->beginTransaction();
$sql1 = $con->prepare("query_to_update_tb1");
$sql2 = $con->prepare("query_to_insert_tb2");
$sql1->execute();
$sql2->execute();
...
$sql3 = $con->prepare("query_to_insert_tb1");
$sql4 = $con->prepare("query_to_insert_tb2");
$sql3->execute();
$sql4->execute();
$con->commit();
}
catch(Exception $e)
{
$con->rollback();
}
Never mind. The user was submiting multiple forms, then the duplicate fields. Nothing wrong with the code.

Insertig php array in mysql DB - Syntax correct, values are not inserted

I have writen this pice of code that should insert into my Database some event data, but it does not insert a thing in the DB, can you tell me why?
try {
$pdo = new PDO("mysql:host={$dbhost};dbname={$dbname}", $dbuser, $dbpass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch( PDOException $excepiton ) {
echo "Connection error :" . $excepiton->getMessage();
}
try{
$sql = "INSERT INTO events_DB (event_id, event_end_time, event_location, event_name) VALUES (:event_id, :event_end_time, :event_location, :event_name) ON DUPLICATE KEY UPDATE event_id = :event_id, event_end_time = :event_end_time, event_location = :event_location, event_name = :event_name";
$stm = $db->prepare($sql);
$stm->execute(array(":event_id" => $event[id], ":event_end_time" => $event[end_time], ":event_location" => $event[location], ":event_name" => $event[name]));
}
catch ( PDOException $exception )
{
// decomentati sa vedeti erorile
echo "PDO error :" . $exception->getMessage();
}
Thanks
The code you've posted is different than the code you're running as the posted code would result in a syntax error at parse time and never actually run.
However, what's happening is the SQL being sent to the prepare method is not valid in some way so that the result returned and stored in $stm is a boolean (false) rather than a valid statement object. Double check your SQL (you could try running it in another application such as phpMyAdmin or via the mysql command-line program) to ensure its validity. You could also add some error handling to find the cause with:
$stm = $db->prepare($sql);
if (!$stm) {
die($db->errorInfo());
}
Edit: You've modified the posted source code which now shows use of exception handling. However, you've commented out the line that echos the exception message. This information will be useful in telling you what's causing the error condition. Uncomment to see the message (which will most likely inform you that the SQL is invalid and which part of it caused the error).
Try to remove the <br> tag from the first line and a " is messing
$sql = "INSERT INTO events_DB (event_id, event_end_time, event_location, event_name);"

How can I implement commit/rollback for MySQL in PHP?

Well basically I have this script that takes a long time to execute and occasionally times out and leaves semi-complete data floating around my database. (Yes I know in a perfect world I would fix THAT instead of implementing commits and rollbacks but I am forced to not do that)
Here is my basic code (dumbed down for simplicity):
$database = new PDO("mysql:host=host;dbname=mysql_db","username","password");
while (notDone())
{
$add_row = $database->prepare("INSERT INTO table (columns) VALUES (?)");
$add_row->execute(array('values'));
//PROCESSING STUFF THAT TAKES A LONG TIME GOES HERE
}
$database = null;
So my problem is that if that if the entire process within that while loop isn't complete then I don't want the row inserted to remain there. I think that somehow I could use commits/rollbacks at the beginning and end of the while loop to do this but don't know how.
Take a look at this tutorial on transactions with PDO.
Basically wrap the long running code in:
$dbh->beginTransaction();
...
$dbh->commit();
And according to this PDO document page:
"When the script ends or when a connection is about to be closed, if you have an outstanding transaction, PDO will automatically roll it back. "
So you will lose the transaction that was pending when the script timed out.
But really, you ought to redesign this so that it doesn't depend on the scriipt staying alive.
You need to use InnoDB based tables for transactions then use any library like PDO or MySQLi that supports them.
try
{
$mysqli->autocommit(FALSE);
$mysqli->query("insert into tblbook (id,cid,book) values('','3','book3.1')");
echo $q_ins=$mysqli->affected_rows."<br>";
$mysqli->query("update tblbook set book='book3' where cid='3'");
echo $q_upd=$mysqli->affected_rows."<br>";
$mysqli->commit();
}
catch(PDOException $e)
{
$mysqli->rollback();
echo $sql . '<br />' . $e->getMessage();
}
<?php
//This may help someone....This code commit the transactions
//only if both queries insert and update successfully runs
$mysqli=new mysqli("localhost","user_name","password","db_name");
if(mysqli_connect_errno())
{
echo "Connection failed: ".mysqli_connect_error();
}
else
{
$mysqli->autocommit(FALSE);
$mysqli->query("insert into tblbook (id,cid,book) values('','3','book3.1')");
echo $q_ins=$mysqli->affected_rows."<br>";
$mysqli->query("update tblbook set book='book3' where cid='3'");
echo $q_upd=$mysqli->affected_rows."<br>";
if($q_ins==1 && $q_upd==1)
{
$mysqli->commit();
echo "Commit<br>";
}
else
{
$mysqli->rollback();
echo "Rollback<br>";
}
}
?>

Categories