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();
}
Related
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.
I have a PHP psql query. I am doing try catch to prevent Duplicates. When I ran the script I can see it's inserting something into my DB. But when I check my DB it's empty.
foreach($data as $n){
$query = $psql->pdo_prepared("INSERT INTO students(id,email,address,phone)VALUES".myFunction($array);
}
and I have a PHP class to handle the exception:
public function pdo_prepared($query,array){
try{
// some logic
}
catch(EXCEPTION $e){
//empty
}
}
The reason why I am doing try catch is to catch duplicates and ignore it. If I throw an exception in my catch block my insert statement won't execute because my current data contains duplicates.
I use Yii and recently started using Transactions with try / catch blocks.
Here's how the code looks right now:
$dbConnection = Yii::app()->db();
try {
$transaction = $dbConnection->beginTransaction();
$dbConnection->createCommand("SELECT * from table_1")
->queryAll();
$transaction->commit();
} catch (Exception $ex) {
$transaction->rollback();
}
Suppose there's an exception with the DB (it's come up while unit-testing), I'm unable to rollback because the PHP dies with a fatal $transaction undefined error.
I'd rather not include isset() checks everywhere..
Is there a simpler way to make this work?
You can check if the exception is an instance of CDbException
$dbConnection = Yii::app()->db();
try {
$transaction = $dbConnection->beginTransaction();
$dbConnection->createCommand("SELECT * from table_1")
->queryAll();
$transaction->commit();
} catch (Exception $ex) {
if ($ex instanceof CDbException)
{
// handle CDBException
// ...
}
$transaction->rollback();
}
This question is about the best way to execute code outside of try block only if no exception is thrown.
try {
//experiment
//can't put code after experiment because I don't want a possible exception from this code to be caught by the following catch. It needs to bubble.
} catch(Exception $explosion) {
//contain the blast
} finally {
//cleanup
//this is not the answer since it executes even if an exception occured
//finally will be available in php 5.5
} else {
//code to be executed only if no exception was thrown
//but no try ... else block exists in php
}
This is method suggested by #webbiedave in response to the question php try .. else. I find it unsatisfactory because of the use of the extra $caught variable.
$caught = false;
try {
// something
} catch (Exception $e) {
$caught = true;
}
if (!$caught) {
}
So what is a better (or the best) way to accomplish this without the need for an extra variable?
One possibility is to put the try block in a method, and return false if an exception is cought.
function myFunction() {
try {
// Code that throws an exception
} catch(Exception $e) {
return false;
}
return true;
}
Have your catch block exit the function or (re)throw/throw an exception. You can filter your exceptions as well. So if your other code also throws an exception you can catch that and (re)throw it. Remember that:
Execution continues if no exception is caught.
If an exception happens and is caught and not (re)throw or a new one throw.
You don't exit your function from the catch block.
It's always a good idea to (re)throw any exception that you don't handle.
We should always be explicit in our exception handling. Meaning if you catch exceptions check the error that we can handle anything else should be (re)throw(n)
The way I would handle your situation would be to (re)throw the exception from the second statement.
try {
$this->throwExceptionA();
$this->throwExceptionB();
} catch (Exception $e) {
if($e->getMessage() == "ExceptionA Message") {
//Do handle code
} elseif($e->getMessage() == "ExceptionB Message") {
//Do other clean-up
throw $e;
} else {
//We should always do this or we will create bugs that elude us because
//we are catching exception that we are not handling
throw $e;
}
}
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) {
}