Do I have to rollBack() before exit()? - php

I have code like this
try {
$pdo->beginTransaction();
$stmt = $pdo->prepare($query1);
$stmt->execute($x);
} catch (Exception $e) {
$pdo->rollBack();
throw->$e;
}
if (condition) {
exit();
}
$x['column1'] = 'string1';
$x['column2'] = 'string2';
$x['column3'] = 'string3';
try {
$stmt = $pdo->prepare($query2);
$stmt->execute($x);
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
throw->$e;
}
If the if condition succeeded and the code did exit()
Is everything related to the $pdo is safe too or do I add before exit() a $pdo->rollBack();?

Technically you don't.
PHP will close the database connection on exit.
Database will roll back all active transactions on close.
However, it is quite unlikely that such a case will ever happen in your code because right now it is wrong. You have to wrap the entire transaction in a try catch, not just database operations. Otherwise, if an exception will be thrown in your "condition" part, it will break a transaction but won't be caught.
Besides, using exit is a bad practice by itself and amidst a transaction a tenfold.
But if you really really need that (in reality you don't) then do something like
try {
$pdo->beginTransaction();
$stmt = $pdo->prepare($query1);
$stmt->execute($x);
if (condition) {
throw new Exception("Stopped on condition");
}
$x['column1'] = 'string1';
$x['column2'] = 'string2';
$x['column3'] = 'string3';
$stmt = $pdo->prepare($query2);
$stmt->execute($x);
$pdo->commit();
} catch (Throwable $e) {
$pdo->rollBack();
throw->$e;
}

From the docs:
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.
https://www.php.net/manual/en/pdo.transactions.php
In my opinion, it's better to run rollback to make sure to other devs that it's not code garbage, someon think about it.

Related

Neo4j, graphaware: After catching an exception, another query will not execute.

I am connecting to neo4j the normal way and i can run queries no problem.
During testing, i wrote a query that should fail (due to uniqueness constraint), the query does fail as expected and i catch the exception.
The problem is when i try to execute the next query in the queue, it just hangs (longer than timeout).
I don't suppose that is normal behavior.
try{
$result = $neo->run ($query);
}
catch (Exception $e) {
// handle it
}
// all good so far
// now we attempt:
try{
$result = $neo->run ($next_query);
}
catch (Exception $e) {
// handle it
}
// hangs longer than timeout
if i remove the failed query from the queue, everything completes
So it seems that the exception thrown by the php-client breaks the connection to neo4j.
If i modify the code to the following, it all works fine.
try{
$result = $neo->run ($query);
}
catch (Exception $e) {
// handle it
connect_to_neo()
}
// all good so far
try{
$result = $neo->run ($next_query);
}
catch (Exception $e) {
// handle it
}
// all good, $next_query gets executed
I do not think that an exception that breaks the connection is desired behavior. Will raise the issue on github.

PHP PDO output user-defined Exceptions

I've got a (example) Oracle Stored Procedure:
CREATE OR REPLACE FUNCTION EXCEPTION_TEST
RETURN NUMBER
AS
BEGIN
raise_application_error(-20500, 'This is the exception text I want to print.');
END;
and I call it in PHP with PDO with the following code:
$statement = $conn->prepare('SELECT exception_test() FROM dual');
$statement->execute();
The call of the function works perfectly fine, but now I want to print the Exception text only.
I read somewhere, that you should not use try and catch with PDO. How can I do this?
You have read that you shouldn't catch an error to report it.
However, if you want to handle it somehow, it's all right to catch it.
Based on the example from my article on handling exception in PDO,
try {
$statement = $conn->prepare('SELECT exception_test() FROM dual');
$statement->execute();
} catch (PDOException $e) {
if ($e->getCode() == 20500 ) {
echo $e->getmessage();
} else {
throw $e;
}
}
Here you are either getting your particular error or re-throwing the exception back to make it handled the usual way
You check the execute response and get the error, for example, like this:
if ($statement->execute() != true) {
echo $statement->errorCode();
echo $statement->errorInfo();
}
You can find more options at the PDO manual.

PDO Transactions. What is the right way to roll back [duplicate]

I'm pretty new to transactions.
Before, what I was doing was something like:
Code Block 1
$db = new PDO(...);
$stmt = $db->prepare(...);
if($stmt->execute()){
// success
return true;
}else{
// failed
return false;
}
But in an attempt to group multiple queries into a single transaction, I'm now using something like:
Code Block 2
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->beginTransaction();
try{
$stmt = $db->prepare(... 1 ...);
$stmt->execute();
$stmt = $db->prepare(... 2 ...);
$stmt->execute();
$stmt = $db->prepare(... 3 ...);
$stmt->execute();
$db->commit();
return true;
}catch(Exception $e){
// Failed, maybe write the error to a txt file or something
$db->rollBack();
return false;
}
My question is: If the transaction fails for whatever reason, does the code stop at $db->commit(); and jump to the catch block? Or would the return true; run first, and then it would try to go to the catch? 'Cause if that's the case, then I've already returned, and so it wouldn't go to the catch. AND it would have returned the wrong value.
Do I still need to include something like:
Code Block 3
if($stmt->commit()){
return true;
}
or is it sufficient the way I have it written in Code Block 2?
If the transaction fails for whatever reason, the code does stop at the very line where error occurred end then the execution jumps directly to the catch block. So it is sufficient the way you have it written in Code Block 2.
Note that you should always re-throw the Exception after rollback. Otherwise you will never have an idea what was a problem. So it should be
try{
$stmt = $db->prepare(... 1 ...);
$stmt->execute();
$stmt = $db->prepare(... 2 ...);
$stmt->execute();
$stmt = $db->prepare(... 3 ...);
$stmt->execute();
$db->commit();
return true;
}catch(Exception $e){
$db->rollBack();
throw $e;
}
The execution is stopped when an exception is thrown.
The first return will not be reached but the catch statement will be executed.
You can even return the commit directly:
$dbh->beginTransaction();
try {
// insert/update query
return $dbh->commit();
} catch (PDOException $e) {
$dbh->rollBack();
return false;
}
if you face any error you can do this to rollback all transactions like this
catch(Exception $e){
$db->rollBack();
// Failed, maybe write the error to a txt file or something
return false;
}

What's **if (no errors)**?

I am trying to implement transactions to Kohana but it seems to be not so easy as in Spring/Java.
So far I found this code to try but I don't know how to replace the part (no errors)
DB::query('START TRANSACTION');
// sql queries with query builder..
if (no errors)
DB::query('COMMIT');
else
DB::query('ROLLBACK');
How do I make the if clause?
Normally transactions are handled as such:
DB::query('START TRANSACTION');
try {
//do something
DB::query('COMMIT');
} catch (Exception $e) {
DB::query('ROLLBACK');
}
What this means is if everything succeeds within the try block, great. If any part of it fails then it won't reach the commit and will jump to the catch block, which contains the rollback. You can add more error handling within the catch if you wish, even throw a new exception of your own or throw the same exception you caught.
Just wrap everything in a try/catch block:
DB::query('START TRANSACTION');
try {
// sql queries with query builder..
DB::query('COMMIT');
} catch (Database_Exception $e) {
DB::query('ROLLBACK');
}
DB errors are converted to exceptions:
DB::query('START TRANSACTION');
try {
// sql queries with query builder..
DB::query('COMMIT');
}
catch($e)
{
$this->template->body = new View('db_error');
$this->template->body->error = 'An error occurred ...';
DB::query('ROLLBACK');
}
If you're using Kohana 3:
$db = Database::instance();
$db->begin();
try
{
// Do your queries here
$db->commit();
}
catch (Database_Exception $e)
{
$db->rollback();
}

Too many try/catch block for PDO

In the controllers class files, most of the method functions include try/catch block something like this:
try
{
$stmt = $this->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
//foreach() or so on...
}
catch (Exception $e)
{
//bunch of code...
//save error into database, etc.
//error into json and pass to view file
}
There are a lot of code in the catch block, is there a way to reduce it. Is possible to add "throw exception" in the catch block?
Yes, it is. Try it by yourself. You can always throw a new Exception in a catch block or rethrow the same exception.
try
{
// ...
}
catch (Exception $e)
{
// do whatever you want
throw new Your_Exception($e->getMessage());
// or
throw $e;
}
I don't know what "bunch of code" is. I'm not sure I believe you. If you have that much going on in a catch block you're doing something wrong.
I'd put this kind of code into an aspect if you have AOP available to you.
"Error into database" might throw its own exception. What happens to that?
The only step that I see here that's necessary is routing to the error view.
What does rethrowing the exception do? It's just passing the buck somewhere else. If all these steps don't need to be done, and all you're doing to rethrowing, then don't catch it at all. Let the exception bubble up to where it's truly handled.
You shouldn't be catching Exception. That's much too general. Catch each specific type of Exception with multiple catch statements on your try block:
try {
} catch(PDOException $err) {
} catch(DomainException $err) {
}

Categories