Skip to main content

Database Transaction Helper

RunDbTransaction

RunDbTransaction is a fluent helper for running safe and clean database transactions in Laravel.
It handles edge cases around rollback levels, especially when using custom exceptions like DefaultException (common in our codebase).

⚠️ Why This Matters

When a DefaultException is thrown (one that already performs a rollback), using DB::beginTransaction() with a try-catch around it can lead to double rollback errors or broken transaction levels.

That's the main problem RunDbTransaction solves:

  • It detects if rollback has already happened (e.g. inside DefaultException)

  • Prevents Laravel’s transaction level from going out of sync

  • Lets you catch and handle exceptions cleanly — even continue without rollback if needed

It also works great with regular exceptions that don’t trigger rollback on their own.


✅ Basic Usage

$successful = RunDbTransaction::create()
    ->transaction(fn() => $this->mainTransaction())
    ->run();
  • Always call run() at the end.

  • Returns true if transaction was committed.

  • Returns false if it was rolled back.


⚙️ Methods

transaction(callable $callback)

Defines the main code block that runs inside the transaction.

->transaction(fn() => $this->doSomething())

intercept(callable $handler)

Optional. Runs only if an exception was thrown and rollback hasn’t yet happened.

This is where you can handle something like DefaultException, and still choose to commit the transaction.

->intercept(fn($e) => $this->handleBeforeRollback($e))
  • Return truthy value → Commit happens

  • Return falsy value → Rollback proceeds


catch(callable $handler)

Optional. Runs after rollback. Even if intercept ran but returned false.

->catch(fn($e) => $this->handleAfterRollback($e))

🚀 Full Example with All Handlers


$successful = RunDbTransaction::create()
    ->transaction(fn() => $this->mainTransaction())
    ->intercept(fn($e) => $this->interceptException($e))
    ->catch(fn($e) => $this->catchException($e))
    ->run();

🧪 Force Rollback Manually

IfYou youcan wantforce toa rollback withoutby throwingreturning (e.g.a forspecial simulation/test):flag:

$committed 
php
=
RunDbTransaction::create()
RunDbTransaction::runTransaction(->transaction(function () { $this-this->doSomething(doSomething(); return RunDbTransactionRunDbTransaction:::DO_ROLLBACK;DO_ROLLBACK; }) ->run();
  • Returns false

  • No exception handlers are triggered

  • Transaction is rolled back cleanly


🔁 Shortcuts

RunDbTransaction::runTransaction(fn() => ...)

Basic one-liner with safe rollback handling:

$success 
php
= RunDbTransaction::runTransaction(fn() => $this->mainTransaction());
shorthand for:
$oksuccess = RunDbTransactionRunDbTransaction:::runTransaction(create()
	->transaction(fn() => $thisthis->mainTransaction())
    ->doSomething()run();
Where no handler is needed just transaction and boolean Success / Fail result.

RunDbTransaction::runOrFail(fn() => ...)

Same as above, but rethrows the exception if one happens. When you only need managed transaction block:

php
RunDbTransactionRunDbTransaction:::runOrFail(runOrFail(fn() => $this-this->doSomething(mainTransaction());

Also works with DO_ROLLBACK – in that case it rolls back without throwing.
Also shorthand for:

$successful = RunDbTransaction::create()
    ->transaction(fn() => $this->mainTransaction())
    //This shape is required when intercept handler is needed!
    ->intercept(fn($e) => $this->handleBeforeRollback($e))
    ->catch(function ($e) {
    	throw $e;  //Just rethrows the exception
    })
    ->run();

Use this shorthand when you want error to propagate further and only need save transaction block. 


💡 Summary Table

Method Description
transaction() Required. Code block to wrap in a transaction
intercept() Optional. Runs if exception is thrown before rollback
catch() Optional. Runs after rollback, always gets the exception
run() Executes the transaction logic
runTransaction() Shorthand with rollback detection
runOrFail() Shorthand that rethrows exception
DO_ROLLBACK Special return value to force rollback without exception