I have following code:
try{
$db->beginTransaction();
$handler = $db->prepare(...);
$handler->execute()
$query2 = "INSERT INTO...";
$db->exec($query2);
$db->commit();
}catch (PDOException $e) {
try { $db->rollBack(); } catch (Exception $e2) {}
}
My question is, does the rollBack() rollbacks all changes caused by both, execute() and exec()? The reason for using exec() is that I have to dynamically create the $query2 and this way it is much easier for me.
Any operations performed between the start of a transaction and the point you do the rollback are reversed. Doesn't matter HOW you did those operations - they'll be rolled back.
Of course, this assumes you're using transaction-capable databases/tables. For instance, if your exec() was done on a MyISAM table in MySQL, and the execute() on an InnODB table, then InnoDB operation will get rolled back, but you're stuck on the MyISAM one.
Related
It rare case may be but for some reason I need an outer try catch for a purpose. So I can't able to control individual transactions.
so I have just one outer catch statement.
catch(Exception $e) {
DB::rollback();
Log:error($e->getMessage());
}
But what happened if there is an error before any transactions hasn't initiated. Is rollback cause unexpected damage ?
You can call DB::transactionLevel() to get count:
catch(Exception $e) {
if (0 < DB::transactionLevel()) {
DB::rollback();
}
Log:error($e->getMessage());
}
Reference: Illuminate\Database\ConnectionInterface | Laravel API
ROLLBACK applies to a "transaction", not a "table". There could be multiple tables involved in a transaction, or there could even be no tables yet involved.
ROLLBACK is prepared to do anything needed, even including "nothing". Don't worry.
i wonder how does transaction work.
Question is do I need to rollback if any error/exception occurs, where the Exception will be thrown and never reach the commit() call? If so why and how? and what rollback does exactly?
consider the followings PHP code (some Java code does similar things like so):
public function deleteAll():void{
$stmt = $this->con->prepare(
'DELETE FROM dd WHERE 1'
);
$this->con->begin_transaction();
if(!$stmt->execute()){
throw new Exception($stmt->error);
}
$this->con->commit();
}
public function insert(array $list):void{
$stmt = $this->con->prepare(
'INSERT INTO dd(cc) VALUES(?)'
);
$stmt->bind_param('s', $v);
$this->con->begin_transaction();
foreach($list as $v){
if(!$stmt->execute()){
throw new Exception($stmt->error);
}
}
$this->con->commit();
}
Note:
$this->con is the mysqli connection object (not using PDO, although different but PDO and mysqli will do similar thing like above).
database is MySQL, table using InnoDB engine.
Some people code shows they catch the Exception and do rollback. But I did not since the commit() is never executed if Exception is thrown. Then this let me wonder why does it need to rollback at all.
My assumption is if there are multiple queries to perform at once like the following:
public function replaceAllWith(array $list):void{
$this->con->begin_transaction();
try{
//do both previous queries at once
$this->deleteAll();
$this->insert($list);
$this->con->commit();
}catch(Exception $e){
//error
$this->con->rollback();
}
}
but then it still cannot rollback because each method/function is done and committed by different method and different transaction.
Second Question: Do I do each transaction in each method call, or only invoke transaction in the 'boss/parent' function which only call and coordinate 'subordinate/helper' functions to do work?
Not sure if I'm asking the right questions.
Database Transaction is confusing, many online resources show only the procedural process (commit only or then immediately rollback which make no differences to normal direct query) without OO concepts involved. Please any pros guide and give some advice. tq.
Will try to make this as simple as possible. I'm using throw/catch with my functions. The function takes in a name a description, and an array of users. It adds the name and description to one table, then takes the array of users, and does a seperate function for adding them into a connector table. I set the function up to turn autocommit off until the last user is entered and then commit. The problem is that if one of the users fails to go in (due to a foreign key constraint), the transaction isn't backed out. Does the fact that I'm calling a seperate function "reset" the autocommit and cause it to not work as intended? Am I doing it wrong by putting the rollback in the Catch clause?
try
{
autocommit=0
run insert query
if query fails: throw error, rollback
else
for count of array
run another function (this function does more SQL and throws its own errors if it fails)
autocommit=1
}
catch
{
rollback, autocommit=1;
display error
}
Hopefully I haven't oversimplified the code. Any help would be appreciated.
$this->dbh->beginTransaction();
try {
// do stuff
$this->dbh->commit();
} catch (PDOException $e) {
$this->dbh->rollBack();
throw $e;
}
Should I do
$dbh->beginTransaction();
try{
Or
try{
$dbh->beginTransaction();
It doesn't really matter, it will run the code indifferent of it's position.
But you want to put the rollback() in the catch, and with that setup it's not readable if you put begin outside.
I would vote for inside the try.
It probably doesn't really matter. However, it's better to place the beginTransaction outside the try. When the beginTransaction fails, it should not execute the rollback.
add it inside the try/catch block, so you can catch any PDOException:
try {
$dbh->beginTransaction(); // start transaction
$stmt = $dbh->query($query); // run your query
$dbh->commit(); // commit
} catch(PDOException $ex) { // if exception, catch it
$dbh->rollBack(); // rollback query
echo $ex->getMessage(); // echo exception message
}
In this case it doesn't matter, as beginTransaction will return false on failure. If it threw exceptions, you would want it inside of a nested try block (otherwise you'd execute rollBack() after catching the exception which would fail because no transaction was started).
If you want to catch the possible errors that the beginTranscation method should throw, go for the second one.
I would like to use transaction in some critical areas of my code, but really not for everything I do.
I just learnt that there is an AUTOCOMMIT value that is set to 1 by default, and I should set it to 0 if I want to START TRANSACTION and COMMIT or ROLLBACK.
Is there a better way to handle that autocommit?
How do I know if it is set or not ?
Does it's value change to AUTOCOMMIT=1 on every page that loads?
Using PDO
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->beginTransaction();
try {
// do stuff
$pdo->commit();
} catch (Exception $ex) {
$pdo->rollBack();
throw $ex;
}