Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

k4kuz0's avatar

DB Transaction doesn't appear to rollback properly

Hey guys, I have the following code for a DB transaction.

DB::connection('db2_mysql')->transaction(function() use($milestones){ //Don't delete old milestones unless you're sure you can replace them...
            Milestone::truncate(); //deletes all milestones
            foreach($milestones as $milestone){
                $m = new Milestone();
                $m->number = $milestone->number;
                $m->name = $milestone->name;
                $m->description = $milestone->description;
                $m->save();
            }
        }, 5);

My logic here is that I don't want to truncate the Milestones table without making sure that I add the new ones. I have an error here, in that I'm use object notation to access array elements, (should be $milestone['number']). But anyway when I run the code, the error prevents the new milestones being added, but the Milestone table gets truncated anyway? Is there something I'm writing incorrectly here?

I just get a standard "Trying to access via object notation when it's not an object" error.

0 likes
7 replies
Snapey's avatar

transactions aren't meant to catch errors in your code are they? They catch errors thrown by the database.

do you need to break it down as per manual transactions and then also wrap your code in a try catch block? you can then rollback or commit based on whether your code worked

k4kuz0's avatar

Oh I see, I guess I misunderstood the documentation. here it says "If an exception is thrown within the transaction Closure, the transaction will automatically be rolled back." I guess I thought it meant any kind of PHP error.

So, would this work perhaps?:

DB::beginTransaction();
try{
    Milestone::truncate(); //deletes all milestones
    foreach($milestones as $milestone){
        $m = new Milestone();
        $m->number = $milestone->number;
        $m->name = $milestone->name;
        $m->description = $milestone->description;
        $m->save();
    }
}catch(Exception $e){
    DB::rollback();
}
DB::commit();

(There may be slight errors in the code, I'm just writing the code here since I'm not at my PC)

jjudge's avatar

@k4kuz0 This would do exactly the same way as a closure. The Milestone::truncate(); after the transaction is started, immediately commits and destroys the transaction.

Snapey's avatar
Snapey
Best Answer
Level 122

From this SO http://stackoverflow.com/questions/5972364/mysql-truncate-table-within-transaction

According to this URL, as of MySQL 5.1.32, TRUNCATE TABLE is DDL and NOT DML like DELETE. This means that TRUNCATE TABLE will cause an implicit COMMIT in the middle of a transaction block. So, use DELETE FROM on a table you need to empty instead of TRUNCATE TABLE.

So, if this is correct, the problem is that the truncate will happen regardless of transaction (i.e., you cannot rollback) so you should use delete from instead of truncate.

3 likes
k4kuz0's avatar

Sorry for the late reply, thanks a lot for your help! :D

adebayo23's avatar

Hello everyone, Am having the same problem using Laravel 8, the transaction is saving to DB but I tried to type a wrong table name to see if it will rollback and it didn't roll back.

See code below;

DB::beginTransaction();

        try {
         
        $saveroomtype = RoomType::create(
            [
            'roomtype_name'          =>  $request['Room_Type'],
           

            ] );

            // if($saveroomtype){
        
        $getroomtype=RoomType::latest('id')->first();

        $rate=$request->Rate;
        $rate_id=$request->rate_id;

    for ($j = 0, $n = count($rate_id); $j < $n; $j++) {
            $rateid    = $rate_id[$j];
            $rate= $rate[$j];
            
            
            $saverates= RoomPrice::create(
            [

   
            'Room_Type'          =>   $getroomtype->id,
            'Rate'  =>  $rate?:0,
            'rate_id' 		=> $rateid,
           

            ] );


            }
        
            DB::commit();     
             return response(['message'=>'ALL GOOD'], 200);
 
        }
        catch (Exception $e)
        {
            DB::rollback();
                     
            return response(['message'=>'FAILURE'], 500);
            throw $e;
        }

Please or to participate in this conversation.